using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using GameFrame.Inspector;
using GameFrame.Deterministic;

namespace GameFrame
{
  public abstract partial class FrameBase
  {
    internal unsafe ComponentSet* _componentMasks;
    private unsafe ComponentDataBuffer* _componentBuffers;
    private int _componentBuffersLength;

    public ComponentFilter<T0> Filter<T0>(ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet)) where T0 : unmanaged, IComponent =>
      new ComponentFilter<T0>(this, ComponentSet.Create<T0>(), any, without);

    public ComponentFilter<T0, T1> Filter<T0, T1>(ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1>(this, ComponentSet.Create<T0, T1>(), any, without);
    }

    public ComponentFilter<T0, T1, T2> Filter<T0, T1, T2>(ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2>(this, ComponentSet.Create<T0, T1, T2>(), any, without);
    }

    public ComponentFilter<T0, T1, T2, T3> Filter<T0, T1, T2, T3>(
      ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
      where T3 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2, T3>(this, ComponentSet.Create<T0, T1, T2, T3>(), any, without);
    }

    public ComponentFilter<T0, T1, T2, T3, T4> Filter<T0, T1, T2, T3, T4>(
      ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
      where T3 : unmanaged, IComponent
      where T4 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2, T3, T4>(this, ComponentSet.Create<T0, T1, T2, T3, T4>(), any, without);
    }

    public ComponentFilter<T0, T1, T2, T3, T4, T5> Filter<T0, T1, T2, T3, T4, T5>(
      ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
      where T3 : unmanaged, IComponent
      where T4 : unmanaged, IComponent
      where T5 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2, T3, T4, T5>(this, ComponentSet.Create<T0, T1, T2, T3, T4, T5>(), any,
        without);
    }

    public ComponentFilter<T0, T1, T2, T3, T4, T5, T6> Filter<T0, T1, T2, T3, T4, T5, T6>(
      ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
      where T3 : unmanaged, IComponent
      where T4 : unmanaged, IComponent
      where T5 : unmanaged, IComponent
      where T6 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2, T3, T4, T5, T6>(this, ComponentSet.Create<T0, T1, T2, T3, T4, T5, T6>(),
        any, without);
    }

    public ComponentFilter<T0, T1, T2, T3, T4, T5, T6, T7> Filter<T0, T1, T2, T3, T4, T5, T6, T7>(
      ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
      where T3 : unmanaged, IComponent
      where T4 : unmanaged, IComponent
      where T5 : unmanaged, IComponent
      where T6 : unmanaged, IComponent
      where T7 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2, T3, T4, T5, T6, T7>(this,
        ComponentSet.Create<T0, T1, T2, T3, T4, T5, T6, T7>(), any, without);
    }

    public unsafe T GetSingleton<T>() where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      return singletonRef.IsValid
        ? this.Get<T>(singletonRef)
        : throw new InvalidOperationException(typeof(T).Name + " Singleton Not Found");
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public EntityRef GetSingletonEntityRef<T>() where T : unmanaged, IComponentSingleton =>
      this.GetSingletonEntityRefIndexUnchecked(ComponentTypeId<T>.Id);

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public EntityRef GetSingletonEntityRef(int componentIndex)
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      return this.GetSingletonEntityRefIndexUnchecked(componentIndex);
    }

    internal unsafe EntityRef GetSingletonEntityRefIndexUnchecked(int componentIndex)
    {
      EntityRef singletonRef = this._componentBuffers[componentIndex].SingletonRef;
      return singletonRef.IsValid
        ? singletonRef
        : throw new InvalidOperationException(ComponentTypeId.Type[componentIndex].Name + " Singleton Not Found");
    }

    public unsafe void SetSingleton<T>(T component, EntityRef optionalAddTarget = default(EntityRef))
      where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      if (!singletonRef.IsValid)
      {
        int num1 = (int)this.Add<T>(!(optionalAddTarget == new EntityRef()) ? optionalAddTarget : this.Create(),
          component);
      }
      else
      {
        int num2 = (int)this.Set<T>(singletonRef, component);
      }
    }

    public unsafe void SetSingleton(int componentIndex, void* value, EntityRef optionalAddTarget = default(EntityRef))
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      EntityRef singletonRef = this._componentBuffers[componentIndex].SingletonRef;
      if (!singletonRef.IsValid)
      {
        int num1 = (int)this.Add(optionalAddTarget.Raw == 0UL ? this.Create() : optionalAddTarget, componentIndex,
          value);
      }
      else
      {
        int num2 = (int)this.Set(singletonRef, componentIndex, value);
      }
    }

    public unsafe bool RemoveSingleton<T>() where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      return singletonRef.IsValid && this.Remove<T>(singletonRef);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool RemoveSingleton(Type componentType) =>
      this.RemoveSingleton(ComponentTypeId.GetComponentIndex(componentType));

    public unsafe bool RemoveSingleton(int componentIndex)
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      EntityRef singletonRef = this._componentBuffers[componentIndex].SingletonRef;
      return singletonRef.IsValid && this.RemoveComponentIndexUnchecked(singletonRef, componentIndex);
    }

    public unsafe bool TryGetSingletonEntityRef<T>(out EntityRef entityRef) where T : unmanaged, IComponentSingleton
    {
      ComponentDataBuffer* componentDataBufferPtr = this._componentBuffers + ComponentTypeId<T>.Id;
      entityRef = componentDataBufferPtr->SingletonRef;
      return entityRef.IsValid;
    }

    public unsafe bool TryGetSingletonEntityRef(int componentIndex, out EntityRef entityRef)
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      ComponentDataBuffer* componentDataBufferPtr = this._componentBuffers + componentIndex;
      entityRef = componentDataBufferPtr->SingletonRef;
      return entityRef.IsValid;
    }

    public unsafe bool TryGetSingleton<T>(out T component) where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      if (!singletonRef.IsValid)
      {
        component = default(T);
        return false;
      }

      component = this.Get<T>(singletonRef);
      return true;
    }

    public unsafe T GetOrAddSingleton<T>(EntityRef optionalAddTarget = default(EntityRef))
      where T : unmanaged, IComponentSingleton
    {
      EntityRef entityRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      if (!entityRef.IsValid)
      {
        entityRef = !(optionalAddTarget == new EntityRef()) ? optionalAddTarget : this.Create();
        int num = (int)this.Add<T>(entityRef);
      }

      return this.Get<T>(entityRef);
    }

    internal unsafe T* GetPointerSingleton<T>() where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      return singletonRef.IsValid
        ? this.GetPointer<T>(singletonRef)
        : throw new InvalidOperationException(typeof(T).Name + " Singleton Not Found");
    }

    internal unsafe void* GetPointerSingleton(int componentIndex)
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      EntityRef singletonRef = this._componentBuffers[componentIndex].SingletonRef;
      return singletonRef.IsValid
        ? this.GetPointer(singletonRef, componentIndex)
        : throw new InvalidOperationException(ComponentTypeId.Type[componentIndex].Name + " Singleton Not Found");
    }

    internal unsafe bool TryGetPointerSingleton<T>(out T* component) where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      if (!singletonRef.IsValid)
      {
        component = (T*)null;
        return false;
      }

      component = this.GetPointer<T>(singletonRef);
      return true;
    }

    internal unsafe bool TryGetPointerSingleton(int componentIndex, out void* component)
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      EntityRef singletonRef = this._componentBuffers[componentIndex].SingletonRef;
      if (!singletonRef.IsValid)
      {
        component = (void*)null;
        return false;
      }

      component = this.GetPointer(singletonRef, componentIndex);
      return true;
    }

    internal unsafe T* GetOrAddSingletonPointer<T>(EntityRef optionalAddTarget = default(EntityRef))
      where T : unmanaged, IComponentSingleton
    {
      EntityRef entityRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      if (!entityRef.IsValid)
      {
        entityRef = !(optionalAddTarget == new EntityRef()) ? optionalAddTarget : this.Create();
        int num = (int)this.Add<T>(entityRef);
      }

      return this.GetPointer<T>(entityRef);
    }

    internal unsafe void* GetOrAddSingletonPointer(int componentIndex,
      EntityRef optionalAddTarget = default(EntityRef))
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      EntityRef entityRef = this._componentBuffers[componentIndex].SingletonRef;
      if (!entityRef.IsValid)
      {
        entityRef = optionalAddTarget.IsValid ? optionalAddTarget : this.Create();
        int num = (int)this.Add(entityRef, componentIndex, out void* _);
      }

      return this.GetPointer(entityRef, componentIndex);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void CheckSingletonAndThrowIfNot(int componentIndex)
    {
      if (componentIndex <= 0 || componentIndex >= this._componentBuffersLength)
        throw new IndexOutOfRangeException(string.Format("Component index '{0}' does not identify a valid component.",
          (object)componentIndex));
      if ((ComponentTypeId.Flags[componentIndex] & ComponentFlags.Singleton) == ComponentFlags.None)
        throw new InvalidOperationException(string.Format("Component of index '{0}' is not a singleton.",
          (object)componentIndex));
    }
  }

  partial class FrameBase
  {
    /// <summary>Global entities configuration</summary>
    [Serializable]
    public class EntitiesConfig
    {
      /// <summary>
      /// When "remove component" and "destroy entity" commands should be committed, effectively cleaning and freeing the data from components' buffers.
      /// <remarks>Both commands still take immediate effect from a semantic perspective, e.g.: checking if the entity exists will return false as soon as the "destroy entity" method is called.</remarks>
      /// <remarks>Commiting commands on <see cref="F:Quantum.CommitCommandsModes.OnFrameSimulationBegin" /> will ensure that performing Physics Queries is safe, even after the frame simulation ends (from Unity),
      /// but might result in a larger total amount of memory reserved in case many entities are destroyed AND created in the same frame (analogous for "component removal").</remarks>
      /// </summary>
      [Tooltip(
        "When remove-component and destroy-entity commands should be committed, effectively cleaning and freeing the data from components buffers.\nBoth commands still take immediate effect from a semantic perspective, e.g.: checking if the entity exists will return false as soon as the destroy-entity method is called.\nCommiting commands on OnFrameSimulationBegin will ensure that performing Physics Queries is safe, even after the frame simulation ends (from Unity), but might result in a larger total amount of memory reserved in case many entities are destroyed AND created in the same frame (analogous for component-removal).")]
      public CommitCommandsModes CommitCommandsMode = CommitCommandsModes.OnFrameSimulationBegin;

      /// <summary>
      /// The starting capacity of internal entity and component buffers
      /// </summary>
      [Tooltip("The starting capacity of internal entity and component buffers.\nDefault is 1024.")]
      public int DefaultEntityCapacity = 1024;

      /// <summary>
      /// Default value for how many components are stored together in a continuous block of memory
      /// </summary>
      [Tooltip(
        "Default value for how many components are stored together in a continuous block of memory.\nDefault is 128.")]
      public int DefaultComponentBlockCapacity = 128;

      /// <summary>
      /// Allows overriding config values on a per-component level
      /// </summary>
      [Tooltip("Allows overriding config values on a per-component level.")]
      public FrameBase.EntitiesConfig.ComponentBufferConfig[] ComponentTypeConfiguration;

      public int GetComponentBlockCapacity(Type type)
      {
        if (this.ComponentTypeConfiguration == null)
          return Math.Max(1, this.DefaultComponentBlockCapacity);
        FrameBase.EntitiesConfig.ComponentBufferConfig componentBufferConfig =
          ((IEnumerable<FrameBase.EntitiesConfig.ComponentBufferConfig>)this.ComponentTypeConfiguration)
          .FirstOrDefault<FrameBase.EntitiesConfig.ComponentBufferConfig>(
            (Func<FrameBase.EntitiesConfig.ComponentBufferConfig, bool>)(x => x.Name == type.Name));
        return componentBufferConfig.Name == null
          ? Math.Max(1, this.DefaultComponentBlockCapacity)
          : Math.Max(1, componentBufferConfig.ComponentBlockCapacity);
      }

      [Serializable]
      public struct ComponentBufferConfig
      {
        public string Name;
        public int ComponentBlockCapacity;
      }
    }
  }

  /// <summary>
  ///  The Frame class is the container for all the transient and static game state data, including the API for entities, physics, assets and others.
  /// </summary>
  /// 
  ///             The reason for this is that Systems must be stateless to comply with Quantum's predict/rollback model. Quantum only guarantees determinism if all game state data is fully contained in the Frame class.
  ///             \ingroup FrameClass
  ///             \ingroup EntityApi
  public abstract class FrameBase : DeterministicFrame
  {
    internal const int COMPONENT_START_INDEX = 1;
    internal const int CULLED_WORD_BYTE_SIZE = 8;
    internal const int CULLED_WORD_BIT_SIZE = 64;
    internal const int COMPONENT_MASK_WORD_BYTESIZE = 4;
    internal const int COMPONENT_MASK_WORD_BITSIZE = 32;
    private int _usedCount;
    private int _freeCount;
    private int _freeHead;
    internal int _capacity;
    private int _capacityActual;
    internal unsafe EntityInfo* _info;
    internal unsafe long* _culled;
    private unsafe ushort* _sparse;
    internal unsafe ComponentSet* _componentMasks;
    private unsafe ComponentDataBuffer* _componentBuffers;
    private int _componentBuffersLength;
    private FrameContext _context;
    protected internal FrameBase.ComponentReactiveCallbackInvoker[] _ComponentSignalsOnAdded;
    protected internal FrameBase.ComponentReactiveCallbackInvoker[] _ComponentSignalsOnRemoved;
    protected internal FrameBase.EntityPrototypeMaterializedCallbackInvoker _SignalOnEntityPrototypeMaterialized;

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    protected unsafe Quantum.Allocator.Heap* _heap;

    protected internal readonly DynamicAssetDB _dynamicAssetDB = new DynamicAssetDB();
    public FrameBase.FrameBaseUnsafe Unsafe;

    /// <summary>Access to the Physics2D API.</summary>
    /// 
    ///             \ingroup FrameClass
    public PhysicsEngine2D.Api Physics2D;

    /// <summary>Access to the Physics3D API.</summary>
    /// 
    ///             \ingroup FrameClass
    public PhysicsEngine3D.Api Physics3D;

    public const int DefaultInitialCollectionCapacity = 8;

    public ComponentFilter<T0> Filter<T0>(ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet)) where T0 : unmanaged, IComponent =>
      new ComponentFilter<T0>(this, ComponentSet.Create<T0>(), any, without);

    public ComponentFilter<T0, T1> Filter<T0, T1>(ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1>(this, ComponentSet.Create<T0, T1>(), any, without);
    }

    public ComponentFilter<T0, T1, T2> Filter<T0, T1, T2>(ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2>(this, ComponentSet.Create<T0, T1, T2>(), any, without);
    }

    public ComponentFilter<T0, T1, T2, T3> Filter<T0, T1, T2, T3>(
      ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
      where T3 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2, T3>(this, ComponentSet.Create<T0, T1, T2, T3>(), any, without);
    }

    public ComponentFilter<T0, T1, T2, T3, T4> Filter<T0, T1, T2, T3, T4>(
      ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
      where T3 : unmanaged, IComponent
      where T4 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2, T3, T4>(this, ComponentSet.Create<T0, T1, T2, T3, T4>(), any, without);
    }

    public ComponentFilter<T0, T1, T2, T3, T4, T5> Filter<T0, T1, T2, T3, T4, T5>(
      ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
      where T3 : unmanaged, IComponent
      where T4 : unmanaged, IComponent
      where T5 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2, T3, T4, T5>(this, ComponentSet.Create<T0, T1, T2, T3, T4, T5>(), any,
        without);
    }

    public ComponentFilter<T0, T1, T2, T3, T4, T5, T6> Filter<T0, T1, T2, T3, T4, T5, T6>(
      ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
      where T3 : unmanaged, IComponent
      where T4 : unmanaged, IComponent
      where T5 : unmanaged, IComponent
      where T6 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2, T3, T4, T5, T6>(this, ComponentSet.Create<T0, T1, T2, T3, T4, T5, T6>(),
        any, without);
    }

    public ComponentFilter<T0, T1, T2, T3, T4, T5, T6, T7> Filter<T0, T1, T2, T3, T4, T5, T6, T7>(
      ComponentSet without = default(ComponentSet),
      ComponentSet any = default(ComponentSet))
      where T0 : unmanaged, IComponent
      where T1 : unmanaged, IComponent
      where T2 : unmanaged, IComponent
      where T3 : unmanaged, IComponent
      where T4 : unmanaged, IComponent
      where T5 : unmanaged, IComponent
      where T6 : unmanaged, IComponent
      where T7 : unmanaged, IComponent
    {
      return new ComponentFilter<T0, T1, T2, T3, T4, T5, T6, T7>(this,
        ComponentSet.Create<T0, T1, T2, T3, T4, T5, T6, T7>(), any, without);
    }

    public unsafe T GetSingleton<T>() where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      return singletonRef.IsValid
        ? this.Get<T>(singletonRef)
        : throw new InvalidOperationException(typeof(T).Name + " Singleton Not Found");
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public EntityRef GetSingletonEntityRef<T>() where T : unmanaged, IComponentSingleton =>
      this.GetSingletonEntityRefIndexUnchecked(ComponentTypeId<T>.Id);

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public EntityRef GetSingletonEntityRef(int componentIndex)
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      return this.GetSingletonEntityRefIndexUnchecked(componentIndex);
    }

    internal unsafe EntityRef GetSingletonEntityRefIndexUnchecked(int componentIndex)
    {
      EntityRef singletonRef = this._componentBuffers[componentIndex].SingletonRef;
      return singletonRef.IsValid
        ? singletonRef
        : throw new InvalidOperationException(ComponentTypeId.Type[componentIndex].Name + " Singleton Not Found");
    }

    public unsafe void SetSingleton<T>(T component, EntityRef optionalAddTarget = default(EntityRef))
      where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      if (!singletonRef.IsValid)
      {
        int num1 = (int)this.Add<T>(!(optionalAddTarget == new EntityRef()) ? optionalAddTarget : this.Create(),
          component);
      }
      else
      {
        int num2 = (int)this.Set<T>(singletonRef, component);
      }
    }

    public unsafe void SetSingleton(int componentIndex, void* value, EntityRef optionalAddTarget = default(EntityRef))
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      EntityRef singletonRef = this._componentBuffers[componentIndex].SingletonRef;
      if (!singletonRef.IsValid)
      {
        int num1 = (int)this.Add(optionalAddTarget.Raw == 0UL ? this.Create() : optionalAddTarget, componentIndex,
          value);
      }
      else
      {
        int num2 = (int)this.Set(singletonRef, componentIndex, value);
      }
    }

    public unsafe bool RemoveSingleton<T>() where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      return singletonRef.IsValid && this.Remove<T>(singletonRef);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool RemoveSingleton(Type componentType) =>
      this.RemoveSingleton(ComponentTypeId.GetComponentIndex(componentType));

    public unsafe bool RemoveSingleton(int componentIndex)
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      EntityRef singletonRef = this._componentBuffers[componentIndex].SingletonRef;
      return singletonRef.IsValid && this.RemoveComponentIndexUnchecked(singletonRef, componentIndex);
    }

    public unsafe bool TryGetSingletonEntityRef<T>(out EntityRef entityRef) where T : unmanaged, IComponentSingleton
    {
      ComponentDataBuffer* componentDataBufferPtr = this._componentBuffers + ComponentTypeId<T>.Id;
      entityRef = componentDataBufferPtr->SingletonRef;
      return entityRef.IsValid;
    }

    public unsafe bool TryGetSingletonEntityRef(int componentIndex, out EntityRef entityRef)
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      ComponentDataBuffer* componentDataBufferPtr = this._componentBuffers + componentIndex;
      entityRef = componentDataBufferPtr->SingletonRef;
      return entityRef.IsValid;
    }

    public unsafe bool TryGetSingleton<T>(out T component) where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      if (!singletonRef.IsValid)
      {
        component = default(T);
        return false;
      }

      component = this.Get<T>(singletonRef);
      return true;
    }

    public unsafe T GetOrAddSingleton<T>(EntityRef optionalAddTarget = default(EntityRef))
      where T : unmanaged, IComponentSingleton
    {
      EntityRef entityRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      if (!entityRef.IsValid)
      {
        entityRef = !(optionalAddTarget == new EntityRef()) ? optionalAddTarget : this.Create();
        int num = (int)this.Add<T>(entityRef);
      }

      return this.Get<T>(entityRef);
    }

    internal unsafe T* GetPointerSingleton<T>() where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      return singletonRef.IsValid
        ? this.GetPointer<T>(singletonRef)
        : throw new InvalidOperationException(typeof(T).Name + " Singleton Not Found");
    }

    internal unsafe void* GetPointerSingleton(int componentIndex)
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      EntityRef singletonRef = this._componentBuffers[componentIndex].SingletonRef;
      return singletonRef.IsValid
        ? this.GetPointer(singletonRef, componentIndex)
        : throw new InvalidOperationException(ComponentTypeId.Type[componentIndex].Name + " Singleton Not Found");
    }

    internal unsafe bool TryGetPointerSingleton<T>(out T* component) where T : unmanaged, IComponentSingleton
    {
      EntityRef singletonRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      if (!singletonRef.IsValid)
      {
        component = (T*)null;
        return false;
      }

      component = this.GetPointer<T>(singletonRef);
      return true;
    }

    internal unsafe bool TryGetPointerSingleton(int componentIndex, out void* component)
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      EntityRef singletonRef = this._componentBuffers[componentIndex].SingletonRef;
      if (!singletonRef.IsValid)
      {
        component = (void*)null;
        return false;
      }

      component = this.GetPointer(singletonRef, componentIndex);
      return true;
    }

    internal unsafe T* GetOrAddSingletonPointer<T>(EntityRef optionalAddTarget = default(EntityRef))
      where T : unmanaged, IComponentSingleton
    {
      EntityRef entityRef = this._componentBuffers[ComponentTypeId<T>.Id].SingletonRef;
      if (!entityRef.IsValid)
      {
        entityRef = !(optionalAddTarget == new EntityRef()) ? optionalAddTarget : this.Create();
        int num = (int)this.Add<T>(entityRef);
      }

      return this.GetPointer<T>(entityRef);
    }

    internal unsafe void* GetOrAddSingletonPointer(int componentIndex, EntityRef optionalAddTarget = default(EntityRef))
    {
      this.CheckSingletonAndThrowIfNot(componentIndex);
      EntityRef entityRef = this._componentBuffers[componentIndex].SingletonRef;
      if (!entityRef.IsValid)
      {
        entityRef = optionalAddTarget.IsValid ? optionalAddTarget : this.Create();
        int num = (int)this.Add(entityRef, componentIndex, out void* _);
      }

      return this.GetPointer(entityRef, componentIndex);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void CheckSingletonAndThrowIfNot(int componentIndex)
    {
      if (componentIndex <= 0 || componentIndex >= this._componentBuffersLength)
        throw new IndexOutOfRangeException(string.Format("Component index '{0}' does not identify a valid component.",
          (object)componentIndex));
      if ((ComponentTypeId.Flags[componentIndex] & ComponentFlags.Singleton) == ComponentFlags.None)
        throw new InvalidOperationException(string.Format("Component of index '{0}' is not a singleton.",
          (object)componentIndex));
    }

    public static unsafe void Print(
      FrameBase r,
      FramePrinter printer,
      bool printComponentsChecksum = false)
    {
      printer.ScopeBegin();
      FrameChecksumerBitStream stream = (FrameChecksumerBitStream)null;
      FrameSerializer serializer = (FrameSerializer)null;
      if (printComponentsChecksum)
      {
        stream = new FrameChecksumerBitStream();
        serializer = new FrameSerializer(DeterministicFrameSerializeMode.Serialize, r, (IBitStream)stream)
        {
          Writing = true
        };
      }

      for (int index = 0; index < r._usedCount; ++index)
      {
        EntityInfo* entityInfoPtr = r._info + index;
        bool flag = (entityInfoPtr->Ref.Version & int.MinValue) == int.MinValue;
        printer.LineBegin(string.Format("Entity #{0}", (object)index));
        if (flag)
          printer.LineEnd();
        else
          printer.LineEnd(" <INACTIVE>");
        printer.ScopeBegin();
        printer.AddPointer<EntityInfo>("Info", r._info + index);
        if (flag)
        {
          printer.AddLine("Components: ");
          printer.ScopeBegin();
          for (int componentIndex = 1; componentIndex < r._componentBuffersLength; ++componentIndex)
          {
            if (r.Has(entityInfoPtr->Ref, componentIndex))
            {
              void* dataPointer = r._componentBuffers[componentIndex].GetDataPointer(entityInfoPtr->Ref);
              printer.AddPointer(ComponentTypeId.Type[componentIndex].Name, dataPointer,
                ComponentTypeId.Type[componentIndex]);
              if (printComponentsChecksum)
              {
                stream.Checksum = 0UL;
                serializer.Reset();
                ComponentTypeId.Callbacks[componentIndex].Serialize(dataPointer, serializer);
                printer.ScopeBegin();
                printer.AddLine(string.Format("<Checksum>: {0}", (object)stream.Checksum));
                printer.ScopeEnd();
              }
            }
          }

          printer.ScopeEnd();
        }

        printer.ScopeEnd();
      }

      printer.ScopeEnd();
    }

    public static unsafe void Serialize(FrameBase r, FrameSerializer serializer)
    {
      Quantum.Assert.Check(r != null);
      Quantum.Assert.Check(r._componentBuffersLength > 0);
      if (serializer.Reading)
      {
        r.Context.ReleaseHeap(r._heap);
        r._heap = r.Context.ReserveHeap();
      }

      if (serializer.Stream.Condition(r.Context.Physics2D != null))
        PhysicsEngine2D.Serialize(r.Context.Physics2D, (IDeterministicFrameSerializer)serializer, r.Context.Allocator);
      if (serializer.Stream.Condition(r.Context.Physics3D != null))
        PhysicsEngine3D.Serialize(r, r.Context.Physics3D, (IDeterministicFrameSerializer)serializer,
          r.Context.Allocator);
      serializer.Stream.Serialize(ref r._usedCount);
      serializer.Stream.Serialize(ref r._freeCount);
      serializer.Stream.Serialize(ref r._freeHead);
      serializer.Stream.Serialize(ref r._capacity);
      if (serializer.Reading)
        r._capacityActual = r._capacity;
      if (serializer.Reading)
      {
        if ((IntPtr)r._info != IntPtr.Zero)
          r.Context.Allocator.Free((void*)r._info);
        r._info = (EntityInfo*)r.Context.Allocator.AllocAndClear(sizeof(EntityInfo) * r._capacity);
      }

      for (int index = 0; index < r._capacity; ++index)
        EntityInfo.Serialize((void*)(r._info + index), serializer);
      if (serializer.Reading)
      {
        if ((IntPtr)r._componentMasks != IntPtr.Zero)
          r.Context.Allocator.Free((void*)r._componentMasks);
        r._componentMasks = (ComponentSet*)r.Context.Allocator.AllocAndClear(sizeof(ComponentSet) * r._capacity);
      }

      for (int index = 0; index < r._capacity; ++index)
        ComponentSet.Serialize((void*)(r._componentMasks + index), serializer);
      if (serializer.Reading)
      {
        if ((IntPtr)r._sparse != IntPtr.Zero)
          r.Context.Allocator.Free((void*)r._sparse);
        r._sparse = (ushort*)r.Context.Allocator.AllocAndClear(2 * r._capacity * r._componentBuffersLength);
      }

      int num1 = r._capacity * r._componentBuffersLength;
      for (int index = 0; index < num1; ++index)
        serializer.Stream.Serialize(r._sparse + index);
      if (serializer.Reading)
      {
        if ((IntPtr)r._culled != IntPtr.Zero)
          r.Context.Allocator.Free((void*)r._culled);
        r._culled = (long*)r.Context.Allocator.Alloc(FrameBase.RoundToCulledByteSize(r._capacity));
      }

      int culledWordCount = FrameBase.RoundToCulledWordCount(r._capacity);
      for (int index = 0; index < culledWordCount; ++index)
        serializer.Stream.Serialize(r._culled + index);
      for (int index1 = 1; index1 < r._componentBuffersLength; ++index1)
      {
        ComponentDataBuffer* componentDataBufferPtr = r._componentBuffers + index1;
        serializer.Stream.Serialize(&componentDataBufferPtr->_count);
        serializer.Stream.Serialize(&componentDataBufferPtr->_pendingRemoval);
        serializer.Stream.Serialize(&componentDataBufferPtr->_version);
        serializer.Stream.Serialize(&componentDataBufferPtr->_blockCapacity);
        serializer.Stream.Serialize(&componentDataBufferPtr->_flags);
        serializer.Stream.Serialize(&componentDataBufferPtr->_singletonSparse);
        if (serializer.Reading)
        {
          componentDataBufferPtr->_componentTypeID = index1;
          componentDataBufferPtr->_stride = ComponentTypeId.GetComponentSize(index1);
          componentDataBufferPtr->_sparse = r._sparse + index1 * r._capacity;
          componentDataBufferPtr->_sparseCapacity = r._capacity;
          componentDataBufferPtr->_blockDataOffset =
            Native.RoundUpToAlignment(sizeof(EntityRef) * componentDataBufferPtr->_blockCapacity, 8);
          componentDataBufferPtr->_blockByteSize = componentDataBufferPtr->_blockDataOffset +
                                                   componentDataBufferPtr->_stride *
                                                   componentDataBufferPtr->_blockCapacity;
          if ((IntPtr)componentDataBufferPtr->_blocksList != IntPtr.Zero)
          {
            for (int index2 = 0; index2 < componentDataBufferPtr->_blocksListCapacity; ++index2)
            {
              ComponentDataBuffer.Block* blockPtr = componentDataBufferPtr->_blocksList + index2;
              if ((IntPtr)blockPtr->PackedHandles != IntPtr.Zero)
                r.Context.Allocator.Free((void*)blockPtr->PackedHandles);
              *blockPtr = new ComponentDataBuffer.Block();
            }

            r.Context.Allocator.Free((void*)componentDataBufferPtr->_blocksList);
            componentDataBufferPtr->_blocksList = (ComponentDataBuffer.Block*)null;
          }
        }

        serializer.Stream.Serialize(&componentDataBufferPtr->_blocksListCount);
        serializer.Stream.Serialize(&componentDataBufferPtr->_blocksListCapacity);
        if (serializer.Reading)
        {
          componentDataBufferPtr->_blocksList =
            (ComponentDataBuffer.Block*)r.Context.Allocator.AllocAndClear(sizeof(ComponentDataBuffer.Block) *
                                                                          componentDataBufferPtr->_blocksListCapacity);
          for (int index3 = 0; index3 < componentDataBufferPtr->_blocksListCapacity; ++index3)
          {
            if (serializer.Stream.ReadBool())
              componentDataBufferPtr->_blocksList[index3] = componentDataBufferPtr->AllocateBlock(r.Context.Allocator);
          }
        }
        else
        {
          for (int index4 = 0; index4 < componentDataBufferPtr->_blocksListCapacity; ++index4)
            serializer.Stream.WriteBool(
              (IntPtr)componentDataBufferPtr->_blocksList[index4].PackedHandles != IntPtr.Zero);
        }

        for (int index5 = 1; index5 < componentDataBufferPtr->_count; ++index5)
        {
          int index6 = index5 / componentDataBufferPtr->_blockCapacity;
          int num2 = index5 % componentDataBufferPtr->_blockCapacity;
          EntityRef* ptr = componentDataBufferPtr->_blocksList[index6].PackedHandles + num2;
          if (serializer.Stream.Writing && !r.Exists(*ptr))
            Quantum.Assert.Check(
              (IntPtr)r.FrameMetaData->_entityDestroyList.Find<EntityRef>(r._heap, *ptr, (uint)ptr->GetHashCode()) !=
              IntPtr.Zero);
          EntityRef.Serialize((void*)ptr, serializer);
          ComponentTypeId.Callbacks[index1]
            .Serialize(
              (void*)(componentDataBufferPtr->_blocksList[index6].PackedData + num2 * componentDataBufferPtr->_stride),
              serializer);
        }
      }
    }

    public static unsafe void Copy(FrameBase to, FrameBase from)
    {
      Quantum.Assert.Check(from._componentBuffersLength == to._componentBuffersLength);
      if (to._capacity != from._capacity)
        to.ChangeCapacity(from._capacity);
      Quantum.Assert.Check(to._capacity == from._capacity);
      Native.Utils.Copy((void*)to._info, (void*)from._info, sizeof(EntityInfo) * from._capacity);
      Native.Utils.Copy((void*)to._componentMasks, (void*)from._componentMasks, sizeof(ComponentSet) * from._capacity);
      Native.Utils.Copy((void*)to._sparse, (void*)from._sparse, 2 * from._capacity * from._componentBuffersLength);
      for (int index = 1; index < to._componentBuffersLength; ++index)
        ComponentDataBuffer.Copy(to.Context.Allocator, to._componentBuffers + index, from._componentBuffers + index);
      to._usedCount = from._usedCount;
      to._freeCount = from._freeCount;
      to._freeHead = from._freeHead;
    }

    protected static unsafe void Initialize(FrameBase f, FrameBase.EntitiesConfig config)
    {
      f._usedCount = 1;
      f._freeCount = 0;
      f._freeHead = 0;
      f._capacity = Math.Max(32, config.DefaultEntityCapacity);
      f._capacityActual = f._capacity;
      f._componentMasks = (ComponentSet*)f.Context.Allocator.AllocAndClear(sizeof(ComponentSet) * f._capacity);
      f.FrameMetaData->_entityDestroyList.Allocate<EntityRef>(f._heap, f._capacity >> 2);
      f.FrameMetaData->_componentRemovalList.Allocate<ComponentReference>(f._heap, f._capacity >> 2);
      f._culled = (long*)f.Context.Allocator.AllocAndClear(FrameBase.RoundToCulledByteSize(f._capacity));
      f._info = (EntityInfo*)f.Context.Allocator.AllocAndClear(sizeof(EntityInfo) * f._capacity);
      f._info->Ref.Version = int.MaxValue;
      f._componentBuffersLength = ComponentTypeId.Type.Length;
      f._componentBuffers =
        (ComponentDataBuffer*)f.Context.Allocator.AllocAndClear(sizeof(ComponentDataBuffer) *
                                                                f._componentBuffersLength);
      for (int index = 1; index < f._componentBuffersLength; ++index)
        f._componentBuffers[index] = ComponentDataBuffer.Create(f.Context.Allocator, config,
          ComponentTypeId.Type[index], ComponentTypeId.Size[index], ComponentTypeId.Flags[index]);
      f._sparse = (ushort*)f.Context.Allocator.AllocAndClear(2 * f._capacity * f._componentBuffersLength);
      for (int index = 1; index < f._componentBuffersLength; ++index)
      {
        f._componentBuffers[index]._sparse = f._sparse + index * f._capacity;
        f._componentBuffers[index]._sparseCapacity = f._capacity;
      }
    }

    public abstract CommitCommandsModes CommitCommandsMode { get; }

    public unsafe void GetAllEntityRefs(List<EntityRef> result)
    {
      result.Clear();
      for (int index = 1; index < this._usedCount; ++index)
      {
        EntityInfo* entityInfoPtr = this._info + index;
        if ((entityInfoPtr->Ref.Version & int.MinValue) == int.MinValue)
          result.Add(entityInfoPtr->Ref);
      }
    }

    /// <summary>Marks all entities as not culled.</summary>
    /// 
    ///             \ingroup Culling
    public unsafe void ClearCulledState() =>
      Native.Utils.Clear((void*)this._culled, FrameBase.RoundToCulledByteSize(this._capacity));

    /// <summary>
    /// Marks a cullable and existing entity as culled.
    /// If the entity does not <see cref="M:Quantum.Core.FrameBase.Exists(Quantum.EntityRef)">Exist</see> or is not cullable, nothing is done.
    /// </summary>
    /// <param name="entityRef">The reference of the entity being culled.</param>
    /// 
    ///             \ingroup Culling
    public unsafe void Cull(EntityRef entityRef)
    {
      if (!this.Exists(entityRef) || (this._info[entityRef.Index].Flags & EntityFlags.NotCullable) != (EntityFlags)0)
        return;
      long* numPtr = this._culled + entityRef.Index / 64;
      *numPtr = *numPtr | 1L << entityRef.Index % 64;
    }

    /// <summary>
    /// If an entity is currently culled from the simulation, regardless of the frame state (Predicted or Verified).
    /// </summary>
    /// <param name="entityRef">The reference of the entity being checked.</param>
    /// <returns>True if the entity is culled OR does NOT <see cref="M:Quantum.Core.FrameBase.Exists(Quantum.EntityRef)">Exist</see>. False otherwise.</returns>
    /// 
    ///             \ingroup Culling
    public unsafe bool IsCulled(EntityRef entityRef) => !this.Exists(entityRef) ||
                                                        (this._culled[entityRef.Index / 64] &
                                                         1L << entityRef.Index % 64) != 0L;

    /// <summary>Sets if an existing entity is cullable or not.</summary>
    /// <param name="entityRef">The reference of the entity being set.</param>
    /// <param name="cullable">If the entity should be cullable (true) or not (false).</param>
    /// 
    ///             \ingroup Culling
    public unsafe void SetCullable(EntityRef entityRef, bool cullable)
    {
      if (!this.Exists(entityRef))
        return;
      EntityInfo* entityInfoPtr = this._info + entityRef.Index;
      if (cullable)
      {
        entityInfoPtr->Flags &= ~EntityFlags.NotCullable;
      }
      else
      {
        entityInfoPtr->Flags |= EntityFlags.NotCullable;
        long* numPtr = this._culled + entityRef.Index / 64;
        *numPtr = *numPtr & ~(1L << entityRef.Index % 64);
      }
    }

    /// <summary>
    /// If an entity can be culled during simulation.
    /// For instance, used by the prediction culling systems to cull entities outside of the prediction area.
    /// </summary>
    /// <param name="entity">The reference of the entity being checked.</param>
    /// <returns>True if the entity exists and can be culled. False otherwise.</returns>
    /// 
    ///             \ingroup Culling
    public unsafe bool IsCullable(EntityRef entity) => this.Exists(entity) &&
                                                       (this._info[entity.Index].Flags & EntityFlags.NotCullable) ==
                                                       (EntityFlags)0;

    /// <summary>Checks if an entity is still valid.</summary>
    /// 
    ///             For example handy for when you store the entity as a reference inside other components.
    ///             <param name="entityRef">Entity reference</param>
    /// <returns>True if the entity exists</returns>
    /// 
    ///             \ingroup EntityApi
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public unsafe bool Exists(EntityRef entityRef) => (uint)entityRef.Index < (uint)this._capacity &&
                                                      this._info[entityRef.Index].Ref.Version == entityRef.Version;

    /// <summary>
    /// Create a component iterator for all components of one type.
    /// </summary>
    /// <typeparam name="T">Component type</typeparam>
    /// <returns>Component iterator</returns>
    /// <remarks>Changed components have to be <see cref="M:Quantum.Core.FrameBase.Set``1(Quantum.EntityRef,``0)" /> back.</remarks>
    /// <remarks>Accessing the component array creates a copy of the component.</remarks>
    /// 
    ///             \ingroup EntityApi
    public unsafe ComponentIterator<T> GetComponentIterator<T>() where T : unmanaged, IComponent
    {
      ComponentDataBuffer* buffer = this._componentBuffers + ComponentTypeId<T>.Id;
      Quantum.Assert.Check(buffer->Stride == sizeof(T));
      return new ComponentIterator<T>(this, buffer);
    }

    internal unsafe ComponentBlockIterator<T> GetComponentBlockIterator<T>() where T : unmanaged, IComponent
    {
      ComponentDataBuffer* buffer = this._componentBuffers + ComponentTypeId<T>.Id;
      Quantum.Assert.Check(buffer->Stride == sizeof(T));
      return new ComponentBlockIterator<T>(this, buffer);
    }

    internal unsafe ComponentBlockIterator<T> GetComponentBlockIterator<T>(int offset, int count)
      where T : unmanaged, IComponent
    {
      ComponentDataBuffer* buffer = this._componentBuffers + ComponentTypeId<T>.Id;
      Quantum.Assert.Check(buffer->Stride == sizeof(T));
      return new ComponentBlockIterator<T>(this, buffer, offset, count);
    }

    /// <summary>Adds a component to an entity.</summary>
    /// <typeparam name="T">Component type</typeparam>
    /// <param name="entity">Entity reference</param>
    /// <param name="value">Value of the component to be added</param>
    /// <remarks>
    /// Internally calls <see cref="M:Quantum.Core.FrameBase.Has``1(Quantum.EntityRef)" /> and <see cref="M:Quantum.Core.FrameBase.Set``1(Quantum.EntityRef,``0)" />
    /// </remarks>
    /// <returns>
    /// <see cref="F:Quantum.AddResult.EntityDoesNotExist" /> if <paramref name="entity" /> does not exist.
    /// <see cref="F:Quantum.AddResult.ComponentAlreadyExists" /> if the <paramref name="entity" /> already has a component of type <typeparamref name="T" />. The value is not set in this case.
    /// <see cref="F:Quantum.AddResult.ComponentAdded" /> Otherwise, indicating that the component was successfully added to the entity.
    /// </returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe AddResult Add<T>(EntityRef entity, T value) where T : unmanaged, IComponent
    {
      if ((uint)entity.Index >= (uint)this._capacity || this._info[entity.Index].Ref.Version != entity.Version)
        return AddResult.EntityDoesNotExist;
      if (this.Has(entity, ComponentTypeId<T>.Id))
        return AddResult.ComponentAlreadyExists;
      int num = (int)this.Set<T>(entity, value);
      return AddResult.ComponentAdded;
    }

    /// <summary>
    /// Adds a component of default value to an entity and returns a pointer to the added component.
    /// </summary>
    /// <typeparam name="T">Component type</typeparam>
    /// <param name="entity">Entity reference</param>
    /// <param name="result">
    /// A pointer to the component added.
    /// Null if the result is not <see cref="F:Quantum.AddResult.ComponentAdded" />.
    /// </param>
    /// <remarks>
    /// Internally calls <see cref="M:Quantum.Core.FrameBase.Has``1(Quantum.EntityRef)" /> and <see cref="M:Quantum.Core.FrameBase.Set``1(Quantum.EntityRef,``0)" />
    /// </remarks>
    /// <returns>
    /// <see cref="F:Quantum.AddResult.EntityDoesNotExist" /> if <paramref name="entity" /> does not exist.
    /// <see cref="F:Quantum.AddResult.ComponentAlreadyExists" /> if the <paramref name="entity" /> already has a component of type <typeparamref name="T" />. The value is not set in this case.
    /// <see cref="F:Quantum.AddResult.ComponentAdded" /> Otherwise, indicating that the component was successfully added to the entity.
    /// </returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe AddResult Add<T>(EntityRef entity, out T* result) where T : unmanaged, IComponent =>
      this.Add<T>(entity, default(T), out result);

    /// <summary>
    /// Adds a component of defined value to an entity and returns a pointer to the added component.
    /// </summary>
    /// <typeparam name="T">Component type</typeparam>
    /// <param name="entity">Entity reference</param>
    /// <param name="value">Value of the component to be added</param>
    /// <param name="result">
    /// A pointer to the component added.
    /// Null if the result is not <see cref="F:Quantum.AddResult.ComponentAdded" />.
    /// </param>
    /// <remarks>
    /// Internally calls <see cref="M:Quantum.Core.FrameBase.Has``1(Quantum.EntityRef)" /> and <see cref="M:Quantum.Core.FrameBase.Set``1(Quantum.EntityRef,``0)" />
    /// </remarks>
    /// <returns>
    /// <see cref="F:Quantum.AddResult.EntityDoesNotExist" /> if <paramref name="entity" /> does not exist.
    /// <see cref="F:Quantum.AddResult.ComponentAlreadyExists" /> if the <paramref name="entity" /> already has a component of type <typeparamref name="T" />. The value is not set in this case.
    /// <see cref="F:Quantum.AddResult.ComponentAdded" /> Otherwise, indicating that the component was successfully added to the entity.
    /// </returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe AddResult Add<T>(EntityRef entity, T value, out T* result) where T : unmanaged, IComponent
    {
      if ((uint)entity.Index < (uint)this._capacity && this._info[entity.Index].Ref.Version == entity.Version)
      {
        if (this.Has(entity, ComponentTypeId<T>.Id))
        {
          result = (T*)null;
          return AddResult.ComponentAlreadyExists;
        }

        int num = (int)this.Set<T>(entity, value);
        result = (T*)this._componentBuffers[ComponentTypeId<T>.Id].GetDataPointer(entity);
        return AddResult.ComponentAdded;
      }

      result = (T*)null;
      return AddResult.EntityDoesNotExist;
    }

    /// <summary>Adds a component of defined value to an entity</summary>
    /// <param name="entity">Entity reference</param>
    /// <param name="componentIndex">
    /// The index of the component to be added.
    /// See also <see cref="M:Quantum.ComponentTypeId.GetComponentIndex(System.Type)" /> or <see cref="P:Quantum.ComponentTypeId`1.Id" /> to retrieve the index of a component type.
    /// </param>
    /// <param name="value">A pointer to data that should be copied as value to the component added.
    /// If null, the component is added with default value.
    /// </param>
    /// <remarks>
    /// Internally calls <see cref="M:Quantum.Core.FrameBase.Has``1(Quantum.EntityRef)" /> and <see cref="M:Quantum.Core.FrameBase.Set``1(Quantum.EntityRef,``0)" />
    /// </remarks>
    /// <returns>
    /// <see cref="F:Quantum.AddResult.EntityDoesNotExist" /> if <paramref name="entity" /> does not exist.
    /// <see cref="F:Quantum.AddResult.ComponentAlreadyExists" /> if the <paramref name="entity" /> already has a component of index <paramref name="componentIndex" />. The value is not set in this case.
    /// <see cref="F:Quantum.AddResult.ComponentAdded" /> Otherwise, indicating that the component was successfully added to the entity.
    /// </returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe AddResult Add(EntityRef entity, int componentIndex, void* value) =>
      this.Add(entity, componentIndex, value, out void* _);

    /// <summary>
    /// Adds a component of default value to an entity and returns a pointer to the added component.
    /// </summary>
    /// <param name="entity">Entity reference</param>
    /// <param name="componentIndex">
    /// The index of the component to be added.
    /// See also <see cref="M:Quantum.ComponentTypeId.GetComponentIndex(System.Type)" /> or <see cref="P:Quantum.ComponentTypeId`1.Id" /> to retrieve the index of a component type.
    /// </param>
    /// <param name="result">
    /// A pointer to the component added.
    /// Null if the result is not <see cref="F:Quantum.AddResult.ComponentAdded" />.
    /// </param>
    /// <remarks>
    /// Internally calls <see cref="M:Quantum.Core.FrameBase.Has``1(Quantum.EntityRef)" /> and <see cref="M:Quantum.Core.FrameBase.Set``1(Quantum.EntityRef,``0)" />
    /// </remarks>
    /// <returns>
    /// <see cref="F:Quantum.AddResult.EntityDoesNotExist" /> if <paramref name="entity" /> does not exist.
    /// <see cref="F:Quantum.AddResult.ComponentAlreadyExists" /> if the <paramref name="entity" /> already has a component of index <paramref name="componentIndex" />. The value is not set in this case.
    /// <see cref="F:Quantum.AddResult.ComponentAdded" /> Otherwise, indicating that the component was successfully added to the entity.
    /// </returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe AddResult Add(EntityRef entity, int componentIndex, out void* result) =>
      this.Add(entity, componentIndex, (void*)null, out result);

    /// <summary>
    /// Adds a component of defined value to an entity and returns a pointer to the added component.
    /// </summary>
    /// <param name="entity">Entity reference</param>
    /// <param name="componentIndex">
    /// The index of the component to be added.
    /// See also <see cref="M:Quantum.ComponentTypeId.GetComponentIndex(System.Type)" /> or <see cref="P:Quantum.ComponentTypeId`1.Id" /> to retrieve the index of a component type.
    /// </param>
    /// <param name="value">A pointer to data that should be copied as value to the component added.
    /// If null, the component is added with default value.
    /// </param>
    /// <param name="result">
    /// A pointer to the component added.
    /// Null if the result is not <see cref="F:Quantum.AddResult.ComponentAdded" />.
    /// </param>
    /// <remarks>
    /// Internally calls <see cref="M:Quantum.Core.FrameBase.Has``1(Quantum.EntityRef)" /> and <see cref="M:Quantum.Core.FrameBase.Set``1(Quantum.EntityRef,``0)" />
    /// </remarks>
    /// <exception cref="T:System.IndexOutOfRangeException">If the <paramref name="componentIndex" /> does not identify a valid component.</exception>
    /// <returns>
    /// <see cref="F:Quantum.AddResult.EntityDoesNotExist" /> if <paramref name="entity" /> does not exist.
    /// <see cref="F:Quantum.AddResult.ComponentAlreadyExists" /> if the <paramref name="entity" /> already has a component of index <paramref name="componentIndex" />. The value is not set in this case.
    /// <see cref="F:Quantum.AddResult.ComponentAdded" /> Otherwise, indicating that the component was successfully added to the entity.
    /// </returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe AddResult Add(
      EntityRef entity,
      int componentIndex,
      void* value,
      out void* result)
    {
      if (componentIndex <= 0 || componentIndex >= this._componentBuffersLength)
        throw new IndexOutOfRangeException(string.Format("Component index '{0}' does not identify a valid component.",
          (object)componentIndex));
      if ((uint)entity.Index < (uint)this._capacity && this._info[entity.Index].Ref.Version == entity.Version)
      {
        if (this.Has(entity, componentIndex))
        {
          result = (void*)null;
          return AddResult.ComponentAlreadyExists;
        }

        int num = (int)this.Set(entity, componentIndex, value);
        result = this._componentBuffers[componentIndex].GetDataPointer(entity);
        return AddResult.ComponentAdded;
      }

      result = (void*)null;
      return AddResult.EntityDoesNotExist;
    }

    /// <summary>
    /// Adds a component of default value to an entity (if it does not have that component yet) and gets a pointer to the component.
    /// </summary>
    /// <param name="entity">Entity reference</param>
    /// <param name="result">
    /// A pointer to the component added or already existing.
    /// Null if the <paramref name="entity" /> does not exist.
    /// </param>
    /// <returns>False if the entity does not exist and True otherwise.</returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe bool AddOrGet<T>(EntityRef entity, out T* result) where T : unmanaged, IComponent
    {
      if ((uint)entity.Index < (uint)this._capacity && this._info[entity.Index].Ref.Version == entity.Version)
      {
        if (!this.Has(entity, ComponentTypeId<T>.Id))
        {
          int num = (int)this.Set<T>(entity, default(T));
        }

        result = (T*)this._componentBuffers[ComponentTypeId<T>.Id].GetDataPointer(entity);
        return true;
      }

      result = (T*)null;
      return false;
    }

    /// <summary>
    /// Adds a component of default value to an entity (if it does not have that component yet) and gets a pointer to the component.
    /// </summary>
    /// <param name="entity">Entity reference</param>
    /// <param name="componentIndex">
    /// The index of the component to be added.
    /// See also <see cref="M:Quantum.ComponentTypeId.GetComponentIndex(System.Type)" /> or <see cref="P:Quantum.ComponentTypeId`1.Id" /> to retrieve the index of a component type.
    /// </param>
    /// <param name="result">A pointer to the component added or already existing. Null if the <paramref name="entity" /> does not exist.</param>
    /// <exception cref="T:System.IndexOutOfRangeException">If the <paramref name="componentIndex" /> does not identify a valid component.</exception>
    /// <returns>False if the entity does not exist and True otherwise.</returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe bool AddOrGet(EntityRef entity, int componentIndex, out void* result)
    {
      if (componentIndex <= 0 || componentIndex >= this._componentBuffersLength)
        throw new IndexOutOfRangeException(string.Format("Component index '{0}' does not identify a valid component.",
          (object)componentIndex));
      if ((uint)entity.Index < (uint)this._capacity && this._info[entity.Index].Ref.Version == entity.Version)
      {
        if (!this.Has(entity, componentIndex))
        {
          int num = (int)this.Set(entity, componentIndex, (void*)null);
        }

        result = this._componentBuffers[componentIndex].GetDataPointer(entity);
        return true;
      }

      result = (void*)null;
      return false;
    }

    /// <summary>Sets a component on an entity.</summary>
    /// <typeparam name="T">Component type</typeparam>
    /// <param name="entity">Entity ref</param>
    /// <param name="value">Value of the component to be added</param>
    /// <returns>
    /// <see cref="F:Quantum.SetResult.EntityDoesNotExist" /> if <paramref name="entity" /> does not exist.
    /// <see cref="F:Quantum.SetResult.ComponentUpdated" /> if the <paramref name="entity" /> already had a component of type <typeparamref name="T" /> that had is value updated to <paramref name="value" />.
    /// <see cref="F:Quantum.SetResult.ComponentAdded" /> Otherwise, indicating that a component with the defined value was added to the entity.
    /// </returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe SetResult Set<T>(EntityRef entity, T value) where T : unmanaged, IComponent
    {
      if (!this.Exists(entity))
        return SetResult.EntityDoesNotExist;
      int id = ComponentTypeId<T>.Id;
      ComponentSet* componentSetPtr = this._componentMasks + entity.Index;
      this._componentBuffers[id].Set<T>(this.Context.Allocator, entity, value);
      bool flag;
      if (flag = !componentSetPtr->IsSet(id))
      {
        componentSetPtr->Add(id);
        if (ComponentTypeId.Callbacks[id].OnAdded != null)
          ComponentTypeId.Callbacks[id].OnAdded(this, entity, this._componentBuffers[id].GetDataPointer(entity));
        if (this._ComponentSignalsOnAdded[id] != null)
          this._ComponentSignalsOnAdded[id](entity, this._componentBuffers[id].GetDataPointer(entity));
      }
      else
        Quantum.Assert.Check(this._componentMasks[entity.Index].IsSet(id));

      return flag ? SetResult.ComponentAdded : SetResult.ComponentUpdated;
    }

    /// <summary>Sets a component on an entity.</summary>
    /// <param name="entity">Entity ref</param>
    /// <param name="componentIndex">
    /// The index of the component being set.
    /// See also <see cref="M:Quantum.ComponentTypeId.GetComponentIndex(System.Type)" /> or <see cref="P:Quantum.ComponentTypeId`1.Id" /> to get the index of a component.
    /// </param>
    /// <param name="value">
    /// A pointer to data that should be copied as value to the component.
    /// If null, the component is set with default value.
    /// </param>
    /// <exception cref="T:System.IndexOutOfRangeException">If the <paramref name="componentIndex" /> does not identify a valid component.</exception>
    /// <returns>
    /// <see cref="F:Quantum.SetResult.EntityDoesNotExist" /> if <paramref name="entity" /> does not exist.
    /// <see cref="F:Quantum.SetResult.ComponentUpdated" /> if the <paramref name="entity" /> already had a component of index <paramref name="componentIndex" /> that had is value updated to <paramref name="value" />.
    /// <see cref="F:Quantum.SetResult.ComponentAdded" /> Otherwise, indicating that a component with the defined value was added to the entity.
    /// </returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe SetResult Set(EntityRef entity, int componentIndex, void* value)
    {
      if (componentIndex <= 0 || componentIndex >= this._componentBuffersLength)
        throw new IndexOutOfRangeException(string.Format("Component index '{0}' does not identify a valid component.",
          (object)componentIndex));
      if (!this.Exists(entity))
        return SetResult.EntityDoesNotExist;
      ComponentSet* componentSetPtr = this._componentMasks + entity.Index;
      this._componentBuffers[componentIndex].Set(this.Context.Allocator, entity, value);
      bool flag;
      if (flag = !componentSetPtr->IsSet(componentIndex))
      {
        componentSetPtr->Add(componentIndex);
        if (ComponentTypeId.Callbacks[componentIndex].OnAdded != null)
          ComponentTypeId.Callbacks[componentIndex]
            .OnAdded(this, entity, this._componentBuffers[componentIndex].GetDataPointer(entity));
        if (this._ComponentSignalsOnAdded[componentIndex] != null)
          this._ComponentSignalsOnAdded[componentIndex](entity,
            this._componentBuffers[componentIndex].GetDataPointer(entity));
      }
      else
        Quantum.Assert.Check(this._componentMasks[entity.Index].IsSet(componentIndex));

      return flag ? SetResult.ComponentAdded : SetResult.ComponentUpdated;
    }

    internal unsafe ComponentDataBuffer* GetComponentDataBuffer<T>() where T : unmanaged, IComponent =>
      this._componentBuffers + ComponentTypeId<T>.Id;

    internal unsafe T* GetPointer<T>(EntityRef entityRef) where T : unmanaged, IComponent
    {
      this.CheckExistsAndThrowIfNot(entityRef);
      return (T*)this._componentBuffers[ComponentTypeId<T>.Id].GetDataPointer(entityRef);
    }

    internal unsafe void* GetPointer(EntityRef entityRef, int componentIndex)
    {
      this.CheckExistsAndThrowIfNot(entityRef);
      this.CheckComponentExistsAndThrowIfNot(componentIndex);
      return this._componentBuffers[componentIndex].GetDataPointer(entityRef);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    internal unsafe bool TryGetPointer<T>(EntityRef entityRef, out T* value) where T : unmanaged, IComponent
    {
      int id = ComponentTypeId<T>.Id;
      if ((uint)entityRef.Index < (uint)this._capacity &&
          this._info[entityRef.Index].Ref.Version == entityRef.Version &&
          (this._componentMasks[entityRef.Index]._set[id / 64] & (ulong)(1L << id % 64)) > 0UL)
      {
        value = (T*)this._componentBuffers[id].GetDataPointerFastUnsafe(entityRef);
        return true;
      }

      value = (T*)null;
      return false;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    internal unsafe bool TryGetPointer(EntityRef entityRef, int componentIndex, out void* value)
    {
      this.CheckComponentExistsAndThrowIfNot(componentIndex);
      if ((uint)entityRef.Index < (uint)this._capacity &&
          this._info[entityRef.Index].Ref.Version == entityRef.Version &&
          (this._componentMasks[entityRef.Index]._set[componentIndex / 64] & (ulong)(1L << componentIndex % 64)) > 0UL)
      {
        value = this._componentBuffers[componentIndex].GetDataPointerFastUnsafe(entityRef);
        return true;
      }

      value = (void*)null;
      return false;
    }

    /// <summary>Gets a component from an entity.</summary>
    /// <typeparam name="T">Component type</typeparam>
    /// <param name="entityRef">Entity reference</param>
    /// <returns>Requested component</returns>
    /// <para>Modified components need to be explicitly written back by using <see cref="M:Quantum.Core.FrameBase.Set``1(Quantum.EntityRef,``0)" />.</para>
    /// <para>Use <see cref="M:Quantum.Core.FrameBase.Has``1(Quantum.EntityRef)" /> to quickly check the entity for component availability.</para>
    /// <example><code>
    /// var t = f.Get&lt;Transform2D&gt;(entity);
    /// t.Position = FPVector2.Zero;
    /// f.Set(entity, t);
    /// </code></example>
    /// <exception cref="T:System.InvalidOperationException">Thrown when the entity does not exist</exception>
    /// <exception cref="T:System.InvalidOperationException">Thrown when the component does not exists on entity</exception>
    /// 
    ///             \ingroup EntityApi
    public unsafe T Get<T>(EntityRef entityRef) where T : unmanaged, IComponent
    {
      this.CheckExistsAndThrowIfNot(entityRef);
      return this._componentBuffers[ComponentTypeId<T>.Id].GetData<T>(entityRef);
    }

    public unsafe bool Has(EntityRef entityRef, int componentIndex)
    {
      Quantum.Assert.Check(componentIndex > 0 && componentIndex < ComponentTypeId.Type.Length);
      return (uint)entityRef.Index < (uint)this._capacity &&
             this._info[entityRef.Index].Ref.Version == entityRef.Version &&
             this._componentMasks[entityRef.Index].IsSet(componentIndex);
    }

    /// <summary>Checks if an entity has a component.</summary>
    /// <typeparam name="T">Component type</typeparam>
    /// <param name="entityRef">Entity reference</param>
    /// <returns>True if the component type exists on the entity</returns>
    /// <exception cref="T:System.InvalidOperationException">Thrown when the entity does not exist</exception>
    /// 
    ///             \ingroup EntityApiT
    public bool Has<T>(EntityRef entityRef) where T : unmanaged, IComponent =>
      this.Has(entityRef, ComponentTypeId<T>.Id);

    /// <summary>
    /// Gets a component from an entity. Does not throw when the component does not exist.
    /// </summary>
    /// <typeparam name="T">Component type</typeparam>
    /// <param name="entityRef">Entity reference</param>
    /// <param name="value">Requested component</param>
    /// <returns>True if the component exists</returns>
    /// <example><code>
    /// if (f.TryGet&lt;Transform2D&gt;(entity, out Transform2D t)) {
    ///   t.Position = FPVector2.Zero;
    ///   f.Set(entity, t);
    /// }
    /// </code></example>
    /// <exception cref="T:System.InvalidOperationException">Thrown when the entity does not exist</exception>
    /// 
    ///             \ingroup EntityApi
    public unsafe bool TryGet<T>(EntityRef entityRef, out T value) where T : unmanaged, IComponent
    {
      int id = ComponentTypeId<T>.Id;
      if ((uint)entityRef.Index < (uint)this._capacity &&
          this._info[entityRef.Index].Ref.Version == entityRef.Version &&
          (this._componentMasks[entityRef.Index]._set[id / 64] & (ulong)(1L << id % 64)) > 0UL)
      {
        value = *(T*)this._componentBuffers[id].GetDataPointerFastUnsafe(entityRef);
        return true;
      }

      value = default(T);
      return false;
    }

    internal unsafe bool RemoveComponentIndexUnchecked(EntityRef entityRef, int componentIndex)
    {
      Quantum.Assert.Check(componentIndex > 0 && componentIndex < ComponentTypeId.Type.Length);
      if (!this.Has(entityRef, componentIndex))
        return false;
      this._componentBuffers[componentIndex].RemovalPending(entityRef);
      this.ComponentRemoveSignals(entityRef, componentIndex);
      this._componentMasks[entityRef.Index].Remove(componentIndex);
      ComponentReference key = new ComponentReference(entityRef, componentIndex);
      QHashCollection.Add<ComponentReference>(this._heap,
        this.FrameMetaData->_componentRemovalList.GetCurrentQHashCollection<ComponentReference>(this._heap), key,
        (uint)key.GetHashCode());
      return true;
    }

    /// <summary>Removes a component from an entity.</summary>
    /// <typeparam name="T">Component type</typeparam>
    /// <param name="entityRef">Entity reference</param>
    /// <returns>False if the <paramref name="entityRef" /> is not valid or the entity does not have a component of type <typeparamref name="T" />. True otherwise.</returns>
    /// 
    ///             \ingroup EntityApi
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool Remove<T>(EntityRef entityRef) where T : unmanaged, IComponent =>
      this.RemoveComponentIndexUnchecked(entityRef, ComponentTypeId<T>.Id);

    /// <summary>Removes a component from an entity.</summary>
    /// <param name="entityRef">Entity reference</param>
    /// <param name="componentType">Component type</param>
    /// <returns>False if the <paramref name="entityRef" /> is not valid or the entity does not have a component of type <paramref name="componentType" />. True otherwise.</returns>
    /// 
    ///             \ingroup EntityApi
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool Remove(EntityRef entityRef, Type componentType) =>
      this.RemoveComponentIndexUnchecked(entityRef, ComponentTypeId.GetComponentIndex(componentType));

    /// <summary>Removes a component from an entity.</summary>
    /// <param name="entityRef">Entity reference</param>
    /// <param name="componentIndex">The index of the component to be removed.</param>
    /// <exception cref="T:System.IndexOutOfRangeException">If the <paramref name="componentIndex" /> does not identify a valid component.</exception>
    /// <returns>False if the <paramref name="entityRef" /> is not valid or the entity does not have a component of index <paramref name="componentIndex" />. True otherwise.</returns>
    /// 
    ///             \ingroup EntityApi
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool Remove(EntityRef entityRef, int componentIndex) =>
      componentIndex > 0 && componentIndex < this._componentBuffersLength
        ? this.RemoveComponentIndexUnchecked(entityRef, componentIndex)
        : throw new IndexOutOfRangeException(string.Format("Component index '{0}' does not identify a valid component.",
          (object)componentIndex));

    internal void CommitAllCommands()
    {
      this.CommitRemoves();
      this.CommitDestroys();
    }

    /// <summary>
    /// Gets a set of all component types that were added to the entity.
    /// </summary>
    /// <param name="entityRef">Entity reference</param>
    /// <returns>A set of all component types that are available on the entity</returns>
    /// 
    ///             \ingroup EntityApi
    public unsafe ComponentSet GetComponentSet(EntityRef entityRef)
    {
      this.CheckExistsAndThrowIfNot(entityRef);
      return this._componentMasks[entityRef.Index];
    }

    /// <summary>
    /// Gets a set of all component types that were added to the entity.
    /// </summary>
    /// <param name="entityRef">Entity reference</param>
    /// <param name="set"></param>
    /// 
    ///             \ingroup EntityApi
    public unsafe bool TryGetComponentSet(EntityRef entityRef, out ComponentSet set)
    {
      if ((uint)entityRef.Index < (uint)this._capacity && this._info[entityRef.Index].Ref.Version == entityRef.Version)
      {
        set = this._componentMasks[entityRef.Index];
        return true;
      }

      set = new ComponentSet();
      return false;
    }

    /// <summary>Check if a destroy is pending for this entity</summary>
    /// <param name="entityRef">Entity reference</param>
    /// <returns>True of destroy is pending, False otherwise</returns>
    public unsafe bool DestroyPending(EntityRef entityRef) => this.Exists(entityRef) &&
                                                              (this._info[entityRef.Index].Flags &
                                                               EntityFlags.DestroyPending) != 0;

    /// <summary>
    /// Destroys the entity and all components that were added to it.
    /// <remarks>
    /// The destruction takes immediate effect, i.e., <see cref="M:Quantum.Core.FrameBase.Exists(Quantum.EntityRef)" /> will start to return false.
    /// The old data, however, will remain in memory until destroy/remove commands are committed,
    /// according to the <see cref="P:Quantum.Core.FrameBase.CommitCommandsMode" /> or manually through <see cref="M:Quantum.Core.FrameBase.FrameBaseUnsafe.CommitAllCommands" />.
    /// </remarks>
    /// </summary>
    /// <example><code>f.Destroy(entity);</code></example>
    /// <param name="entityRef"></param>
    /// 
    ///             \ingroup EntityApi
    public unsafe bool Destroy(EntityRef entityRef)
    {
      if (!this.Exists(entityRef))
        return false;
      EntityInfo* entityInfoPtr = this._info + entityRef.Index;
      entityInfoPtr->Flags |= EntityFlags.DestroyPending;
      ComponentSet componentSet = this._componentMasks[entityRef.Index];
      int num1 = 0;
      label_24:
      for (int index = 0; index < 4; ++index)
      {
        ulong num2 = componentSet._set[index];
        if (num2 == 0UL)
        {
          num1 += 64;
        }
        else
        {
          int num3 = 0;
          while (true)
          {
            uint num4 = *(uint*)((IntPtr) & num2 + (IntPtr)num3 * 4);
            if (num4 > 0U)
            {
              int num5 = 0;
              while (true)
              {
                ushort num6 = *(ushort*)((IntPtr) & num4 + (IntPtr)num5 * 2);
                if (num6 > (ushort)0)
                {
                  int num7 = 0;
                  while (true)
                  {
                    byte num8 = *(byte*)((IntPtr) & num6 + num7);
                    int num9 = 0;
                    for (; num8 > (byte)0; num8 >>= 1)
                    {
                      if (((int)num8 & 1) == 1)
                      {
                        this._componentBuffers[num1 + num9].RemovalPending(entityRef);
                        this.ComponentRemoveSignals(entityRef, num1 + num9);
                      }

                      ++num9;
                    }

                    num1 += 8;
                    if (num7 == 0)
                      ++num7;
                    else
                      break;
                  }
                }
                else
                  num1 += 16;

                if (num5 == 0)
                  ++num5;
                else
                  break;
              }
            }
            else
              num1 += 32;

            if (num3 == 0)
              ++num3;
            else
              goto label_24;
          }
        }
      }

      if (!componentSet.Equals(this._componentMasks[entityRef.Index]))
        Quantum.Log.Error(
          string.Format(
            "At least one component was added or removed to {0} during an OnRemoved signal that was called as the entity was being destroyed. Query IsDestroyPending(EntityRef entityRef) to see if an entity is being destroyed.",
            (object)entityRef), Array.Empty<object>());
      QHashCollection.Add<EntityRef>(this._heap,
        this.FrameMetaData->_entityDestroyList.GetCurrentQHashCollection<EntityRef>(this._heap), entityInfoPtr->Ref,
        (uint)entityInfoPtr->Ref.GetHashCode());
      entityInfoPtr->Ref.Version &= int.MaxValue;
      entityInfoPtr->Ref.Version = entityInfoPtr->Ref.Version + 1 & int.MaxValue;
      return true;
    }

    private unsafe void ChangeCapacity(int newCapacity)
    {
      if (this._capacity < newCapacity)
      {
        if (this._capacityActual >= newCapacity)
        {
          Quantum.Assert.Check(this._capacityActual > 0);
          Quantum.Assert.Check(this._capacity != this._capacityActual);
          int capacity = this._capacity;
          ushort* dest = (ushort*)this.Context.TempAllocate(2 * capacity * this._componentBuffersLength);
          Native.Utils.Copy((void*)dest, (void*)this._sparse, 2 * capacity * this._componentBuffersLength);
          this._capacity = newCapacity;
          for (int index = 1; index < this._componentBuffersLength; ++index)
            this._componentBuffers[index].ChangeEntityCapacity(dest + index * capacity, capacity,
              this._sparse + index * newCapacity, newCapacity);
        }
        else
        {
          Quantum.Assert.Check(this._capacity == this._capacityActual);
          int capacity = this._capacity;
          long* dest = (long*)this.Context.Allocator.AllocAndClear(FrameBase.RoundToCulledByteSize(newCapacity));
          Native.Utils.Copy((void*)dest, (void*)this._culled, FrameBase.RoundToCulledByteSize(this._capacity));
          this._info = (EntityInfo*)this.Context.Allocator.Expand((void*)this._info,
            sizeof(EntityInfo) * this._capacity, sizeof(EntityInfo) * newCapacity);
          this._componentMasks = (ComponentSet*)this.Context.Allocator.Expand((void*)this._componentMasks,
            sizeof(ComponentSet) * this._capacity, sizeof(ComponentSet) * newCapacity);
          this._capacity = newCapacity;
          this._capacityActual = newCapacity;
          ushort* numPtr =
            (ushort*)this.Context.Allocator.AllocAndClear(2 * this._capacity * this._componentBuffersLength);
          for (int index = 1; index < this._componentBuffersLength; ++index)
            this._componentBuffers[index].ChangeEntityCapacity(this._sparse + index * capacity, capacity,
              numPtr + index * newCapacity, newCapacity);
          this.Context.Allocator.Free((void*)this._culled);
          this._culled = dest;
          this.Context.Allocator.Free((void*)this._sparse);
          this._sparse = numPtr;
        }
      }
      else
      {
        if (this._capacity <= newCapacity)
          return;
        int capacity = this._capacity;
        int num = capacity - newCapacity;
        this._capacity = newCapacity;
        for (int index = 1; index < this._componentBuffersLength; ++index)
          this._componentBuffers[index].ChangeEntityCapacity(this._sparse + index * capacity, capacity,
            this._sparse + index * newCapacity, newCapacity);
        Native.Utils.Clear((void*)(this._info + this._capacity), sizeof(EntityInfo) * num);
        int culledByteSize1 = FrameBase.RoundToCulledByteSize(capacity);
        int culledByteSize2 = FrameBase.RoundToCulledByteSize(newCapacity);
        Native.Utils.Clear((void*)((IntPtr)this._culled + culledByteSize2), culledByteSize1 - culledByteSize2);
        Native.Utils.Clear((void*)(this._sparse + this._capacity * this._componentBuffersLength),
          2 * num * this._componentBuffersLength);
        Native.Utils.Clear((void*)(this._componentMasks + this._capacity), sizeof(ComponentSet) * num);
      }
    }

    /// <summary>
    /// Creates an entity from a prototype asset. This process is also reffered to as "prototype materialization".
    /// </summary>
    /// <param name="prototype"></param>
    /// <seealso cref="M:Quantum.Core.FrameBase.Create(Quantum.EntityPrototype)" />
    /// <returns></returns>
    /// 
    ///             \ingroup EntityApi
    public EntityRef Create(AssetRefEntityPrototype prototype) =>
      this.Create(this.FindAsset<EntityPrototype>(prototype.Id));

    /// <summary>
    /// Creates an entity from a prototype. This process is also reffered to as "prototype materialization".
    /// </summary>
    /// 
    ///             The steps are following:
    ///             1. An empty entity is created.
    ///             2. For each component prototype:
    ///               1. Component prototype is materialized.
    ///               2. Component prototype has MaterializeUser invoked.
    ///               3. Component prototype is added to the entity.
    ///             3. <see cref="!:Quantum.ISignalOnEntityPrototypeMaterialized" />
    ///  is invoked.
    ///             <param name="prototype"></param>
    /// <returns></returns>
    /// 
    ///             \ingroup EntityApi
    public EntityRef Create(EntityPrototype prototype)
    {
      EntityRef entity = this.Create();
      EntityPrototypeRef entityPrototypeRef = EntityPrototypeRef.FromPrototypeAsset(prototype);
      this.MaterializePrototypeInternal(entity, prototype.Container, entityPrototypeRef);
      if (prototype.Container.HasAnyListeners)
        this.InvokeEntityPrototypeMaterializedListeners(entity, prototype.Container, entityPrototypeRef);
      FrameBase.EntityPrototypeMaterializedCallbackInvoker prototypeMaterialized =
        this._SignalOnEntityPrototypeMaterialized;
      if (prototypeMaterialized != null)
        prototypeMaterialized(entity, entityPrototypeRef);
      return entity;
    }

    /// <summary>
    /// Creates (materializes) map prototypes. The difference between this method and calling
    /// <see cref="M:Quantum.Core.FrameBase.Create(Quantum.EntityPrototype)" /> repeatedly is that <see cref="T:Quantum.EntityRef" /> fields
    /// get resolved and that <see cref="T:Quantum.MapEntityLink" /> components are added implicitly.
    /// </summary>
    /// 
    ///             This is a multi-step process:
    ///             1. An empty entity is created for each prototype
    ///             2. For each entity-prototype pair:
    ///               1. For each component prototype:
    ///                 1. Component prototype is materialized.
    ///                 2. Component prototype has MaterializeUser invoked.
    ///                 3. Component prototype is added to the entity.
    ///               2. <see cref="T:Quantum.MapEntityLink" />
    ///  component is added to the entity.
    ///             3. <see cref="!:ISignalOnEntityPrototypeMaterialized" />
    ///  is invoked for each entity-prototype pair.
    ///             <param name="prototypes"></param>
    /// <param name="parentAsset"></param>
    /// 
    ///             \ingroup EntityApi
    public void Create(EntityPrototypeContainer[] prototypes, Map parentAsset)
    {
      EntityRef[] mapEntities = new EntityRef[prototypes.Length];
      for (int index = 0; index < prototypes.Length; ++index)
        mapEntities[index] = this.Create();
      bool flag = false;
      for (int internalAssetId = 0; internalAssetId < prototypes.Length; ++internalAssetId)
      {
        this.MaterializePrototypeInternal(mapEntities[internalAssetId], prototypes[internalAssetId],
          EntityPrototypeRef.FromMasterAsset(parentAsset, internalAssetId), mapEntities);
        int num = (int)this.Add<MapEntityLink>(mapEntities[internalAssetId], new MapEntityLink()
        {
          Index = internalAssetId
        });
        flag |= prototypes[internalAssetId].HasAnyListeners;
      }

      if (flag)
      {
        for (int internalAssetId = 0; internalAssetId < prototypes.Length; ++internalAssetId)
        {
          if (prototypes[internalAssetId].HasAnyListeners)
            this.InvokeEntityPrototypeMaterializedListeners(mapEntities[internalAssetId], prototypes[internalAssetId],
              EntityPrototypeRef.FromMasterAsset(parentAsset, internalAssetId));
        }
      }

      if (this._SignalOnEntityPrototypeMaterialized == null)
        return;
      for (int internalAssetId = 0; internalAssetId < prototypes.Length; ++internalAssetId)
        this._SignalOnEntityPrototypeMaterialized(mapEntities[internalAssetId],
          EntityPrototypeRef.FromMasterAsset(parentAsset, internalAssetId));
    }

    /// <summary>
    /// Adds (materializes) components to an already existing entity.
    /// </summary>
    /// <param name="entity"></param>
    /// <param name="prototype"></param>
    /// <returns></returns>
    /// <see cref="M:Quantum.Core.FrameBase.Set(Quantum.EntityRef,Quantum.EntityPrototype)" />
    public SetResult Set(EntityRef entity, AssetRefEntityPrototype prototype) =>
      this.Set(entity, this.FindAsset<EntityPrototype>(prototype.Id));

    /// <summary>
    /// Adds (materializes) components to an already existing entity. If a component already exists,
    /// it will get completely overwritten, but an error message will be logged. To avoid errors in
    /// such case use <see cref="M:Quantum.Core.FrameBase.Set(Quantum.EntityRef,Quantum.EntityPrototype,Quantum.ComponentSet@)" /> instead.
    /// </summary>
    /// 
    ///             The steps are following:
    ///             1. For each component prototype:
    ///               1. Component prototype is materialized.
    ///               2. Component prototype has MaterializeUser invoked.
    ///               3. Component prototype is added to the entity.
    ///             2. <see cref="!:Quantum.ISignalOnEntityPrototypeMaterialized" />
    ///  is invoked.
    ///             <param name="entity"></param>
    /// <param name="prototype"></param>
    /// <returns><see cref="F:Quantum.SetResult.EntityDoesNotExist" /> if entity does not exist. <see cref="F:Quantum.SetResult.ComponentUpdated" /> if any component has been overwritten, <see cref="F:Quantum.SetResult.ComponentAdded" /> otherwise.</returns>
    /// <seealso cref="M:Quantum.Core.FrameBase.Create(Quantum.EntityPrototype)" />
    /// <seealso cref="!:Set(EntityRef, EntityPrototype, out ComponentSet, out ComponentSet)" />
    /// 
    ///             \ingroup EntityApi
    public SetResult Set(EntityRef entity, EntityPrototype prototype)
    {
      if (!this.Exists(entity))
        return SetResult.EntityDoesNotExist;
      EntityPrototypeRef entityPrototypeRef = EntityPrototypeRef.FromPrototypeAsset(prototype);
      bool flag = this.MaterializePrototypeInternal(entity, prototype.Container, entityPrototypeRef);
      if (prototype.Container.HasAnyListeners)
        this.InvokeEntityPrototypeMaterializedListeners(entity, prototype.Container, entityPrototypeRef);
      FrameBase.EntityPrototypeMaterializedCallbackInvoker prototypeMaterialized =
        this._SignalOnEntityPrototypeMaterialized;
      if (prototypeMaterialized != null)
        prototypeMaterialized(entity, entityPrototypeRef);
      return flag ? SetResult.ComponentAdded : SetResult.ComponentUpdated;
    }

    /// <summary>
    /// Adds (materializes) components to an already existing entity.
    /// </summary>
    /// <param name="entity"></param>
    /// <param name="prototype"></param>
    /// <param name="overwrittenComponents"></param>
    /// <returns></returns>
    /// <see cref="M:Quantum.Core.FrameBase.Set(Quantum.EntityRef,Quantum.EntityPrototype,Quantum.ComponentSet@)" />
    public SetResult Set(
      EntityRef entity,
      AssetRefEntityPrototype prototype,
      out ComponentSet overwrittenComponents)
    {
      return this.Set(entity, this.FindAsset<EntityPrototype>(prototype.Id), out overwrittenComponents);
    }

    /// <summary>
    /// Adds (materializes) components to an already existing entity. If a component already exists,
    /// it will get completely overwritten.
    /// </summary>
    /// 
    ///             The steps are following:
    ///             1. For each component prototype:
    ///               1. Component prototype is materialized.
    ///               2. Component prototype has MaterializeUser invoked.
    ///               3. Component prototype is added to the entity.
    ///             2. <see cref="!:Quantum.ISignalOnEntityPrototypeMaterialized" />
    ///  is invoked.
    ///             <param name="entity"></param>
    /// <param name="prototype"></param>
    /// <param name="overwrittenComponents">Components that have been overwritten.</param>
    /// <returns><see cref="F:Quantum.SetResult.EntityDoesNotExist" /> if entity does not exist. <see cref="F:Quantum.SetResult.ComponentUpdated" /> if any component has been overwritten, <see cref="F:Quantum.SetResult.ComponentAdded" /> otherwise.</returns>
    /// <seealso cref="M:Quantum.Core.FrameBase.Create(Quantum.EntityPrototype)" />
    /// 
    ///             \ingroup EntityApi
    public unsafe SetResult Set(
      EntityRef entity,
      EntityPrototype prototype,
      out ComponentSet overwrittenComponents)
    {
      if (!this.Exists(entity))
        return SetResult.EntityDoesNotExist;
      EntityPrototypeRef entityPrototypeRef = EntityPrototypeRef.FromPrototypeAsset(prototype);
      ComponentSet componentSet = new ComponentSet();
      bool flag = this.MaterializePrototypeInternal(entity, prototype.Container, entityPrototypeRef,
        overridenComponents: &componentSet);
      overwrittenComponents = componentSet;
      if (prototype.Container.HasAnyListeners)
        this.InvokeEntityPrototypeMaterializedListeners(entity, prototype.Container, entityPrototypeRef);
      FrameBase.EntityPrototypeMaterializedCallbackInvoker prototypeMaterialized =
        this._SignalOnEntityPrototypeMaterialized;
      if (prototypeMaterialized != null)
        prototypeMaterialized(entity, entityPrototypeRef);
      return flag ? SetResult.ComponentAdded : SetResult.ComponentUpdated;
    }

    private unsafe bool MaterializePrototypeInternal(
      EntityRef entity,
      EntityPrototypeContainer container,
      EntityPrototypeRef prototypeRef,
      EntityRef[] mapEntities = null,
      ComponentSet* overridenComponents = null)
    {
      bool flag = false;
      container.EnsureIsSorted();
      ComponentPrototype[] components = container.Components;
      for (int index = 0; index < components.Length; ++index)
      {
        int componentTypeId = components[index].ComponentTypeId;
        PrototypeMaterializationContext context =
          new PrototypeMaterializationContext(entity, prototypeRef, container, componentTypeId, mapEntities);
        if (!components[index].AddToEntity(this, entity, in context))
        {
          flag = true;
          if ((IntPtr)overridenComponents != IntPtr.Zero)
            overridenComponents->Add(componentTypeId);
          else
            PrototypeValidator.ComponentOverwritten(entity, components[index], in context);
        }
      }

      return flag;
    }

    private void InvokeEntityPrototypeMaterializedListeners(
      EntityRef entity,
      EntityPrototypeContainer container,
      EntityPrototypeRef prototypeRef)
    {
      Quantum.Assert.Check(container.HasAnyListeners);
      foreach (ComponentPrototype component in container.Components)
      {
        if (component is IEntityPrototypeMaterializedListener materializedListener)
          materializedListener.OnEntityPrototypeMaterialized(this, entity, prototypeRef);
      }
    }

    /// <summary>Creates an entity that is saved in the game state.</summary>
    /// <returns>Entity reference</returns>
    /// <example><code>var entity = f.Create();</code></example>
    /// 
    ///             \ingroup EntityApi
    public unsafe EntityRef Create()
    {
      int index;
      EntityInfo* entityInfoPtr;
      if (this._freeHead != 0)
      {
        index = this._freeHead;
        entityInfoPtr = this._info + index;
        this._freeHead = entityInfoPtr->Ref.Index;
        --this._freeCount;
      }
      else
      {
        if (this._usedCount == this._capacity)
          this.ChangeCapacity(this._capacity * 2);
        Quantum.Assert.Check(this._usedCount < this._capacity);
        index = this._usedCount++;
        entityInfoPtr = this._info + index;
        Quantum.Assert.Check(index < this._capacity);
      }

      entityInfoPtr->Ref.Index = index;
      Quantum.Assert.Check(entityInfoPtr->Ref.Version >= 0);
      entityInfoPtr->Ref.Version = entityInfoPtr->Ref.Version + 1 & int.MaxValue;
      entityInfoPtr->Ref.Version |= int.MinValue;
      Quantum.Assert.Check(this._componentMasks[index].IsEmpty);
      return entityInfoPtr->Ref;
    }

    private unsafe void ComponentRemoveSignals(EntityRef entity, int componentIndex)
    {
      if (this._ComponentSignalsOnRemoved[componentIndex] != null)
        this._ComponentSignalsOnRemoved[componentIndex](entity,
          this._componentBuffers[componentIndex].GetDataPointer(entity));
      if (ComponentTypeId.Callbacks[componentIndex].OnRemoved == null)
        return;
      ComponentTypeId.Callbacks[componentIndex]
        .OnRemoved(this, entity, this._componentBuffers[componentIndex].GetDataPointer(entity));
    }

    private unsafe void CommitDestroys()
    {
      QHashCollection* qHash;
      int count;
      this.FrameMetaData->_entityDestroyList.GetQHashCollections(this._heap, out qHash, out count);
      for (int index1 = 0; index1 < count; ++index1)
      {
        QHashCollection* collection = qHash + index1;
        if (collection->UsedCount != 0)
        {
          try
          {
            for (int index2 = 0; index2 < collection->UsedCount; ++index2)
            {
              QHashCollection.Entry* entry = QHashCollection.GetEntry(this._heap, collection, index2);
              Quantum.Assert.Check(entry->State == QHashCollection.EntryState.Used);
              EntityRef key = QHashCollection.GetKey<EntityRef>(this._heap, collection, entry);
              EntityInfo* entityInfoPtr = this._info + key.Index;
              Quantum.Assert.Check((entityInfoPtr->Flags & EntityFlags.DestroyPending) == EntityFlags.DestroyPending);
              ComponentSet componentSet = this._componentMasks[key.Index];
              int num1 = 0;
              label_25:
              for (int index3 = 0; index3 < 4; ++index3)
              {
                ulong num2 = componentSet._set[index3];
                if (num2 == 0UL)
                {
                  num1 += 64;
                }
                else
                {
                  int num3 = 0;
                  while (true)
                  {
                    uint num4 = *(uint*)((IntPtr) & num2 + (IntPtr)num3 * 4);
                    if (num4 > 0U)
                    {
                      int num5 = 0;
                      while (true)
                      {
                        ushort num6 = *(ushort*)((IntPtr) & num4 + (IntPtr)num5 * 2);
                        if (num6 > (ushort)0)
                        {
                          int num7 = 0;
                          while (true)
                          {
                            byte num8 = *(byte*)((IntPtr) & num6 + num7);
                            int num9 = 0;
                            for (; num8 > (byte)0; num8 >>= 1)
                            {
                              if (((int)num8 & 1) == 1)
                                this._componentBuffers[num1 + num9].Remove(key);
                              ++num9;
                            }

                            num1 += 8;
                            if (num7 == 0)
                              ++num7;
                            else
                              break;
                          }
                        }
                        else
                          num1 += 16;

                        if (num5 == 0)
                          ++num5;
                        else
                          break;
                      }
                    }
                    else
                      num1 += 32;

                    if (num3 == 0)
                      ++num3;
                    else
                      goto label_25;
                  }
                }
              }

              this._componentMasks[key.Index] = new ComponentSet();
              entityInfoPtr->Ref.Index = this._freeHead;
              entityInfoPtr->Flags = (EntityFlags)0;
              this._freeHead = key.Index;
              ++this._freeCount;
            }
          }
          finally
          {
            QHashCollection.Clear(this._heap, collection);
          }
        }
        else
          break;
      }

      this.FrameMetaData->_entityDestroyList.Reset(this._heap);
    }

    private unsafe void CommitRemoves()
    {
      QHashCollection* qHash;
      int count;
      this.FrameMetaData->_componentRemovalList.GetQHashCollections(this._heap, out qHash, out count);
      for (int index1 = 0; index1 < count; ++index1)
      {
        QHashCollection* collection = qHash + index1;
        if (collection->UsedCount != 0)
        {
          try
          {
            for (int index2 = 0; index2 < collection->UsedCount; ++index2)
            {
              QHashCollection.Entry* entry = QHashCollection.GetEntry(this._heap, collection, index2);
              Quantum.Assert.Check(entry->State == QHashCollection.EntryState.Used);
              ComponentReference key = QHashCollection.GetKey<ComponentReference>(this._heap, collection, entry);
              EntityRef entity = key.Entity;
              int component = key.Component;
              if ((this._info[entity.Index].Ref.Version & int.MinValue) == 0)
              {
                Quantum.Assert.Check(
                  (IntPtr)this.FrameMetaData->_entityDestroyList.Find<EntityRef>(this._heap, entity,
                    (uint)entity.GetHashCode()) != IntPtr.Zero);
                entity.Version &= int.MaxValue;
                entity.Version = entity.Version + 1 & int.MaxValue;
              }

              if ((uint)entity.Index < (uint)this._capacity && this._info[entity.Index].Ref.Version == entity.Version &&
                  ((long)this._componentMasks[entity.Index]._set[component / 64] & 1L << component % 64) == 0L)
                this._componentBuffers[key.Component].Remove(key.Entity);
            }
          }
          finally
          {
            QHashCollection.Clear(this._heap, collection);
          }
        }
        else
          break;
      }

      this.FrameMetaData->_componentRemovalList.Reset(this._heap);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private unsafe void CheckExistsAndThrowIfNot(EntityRef entityRef)
    {
      if ((uint)entityRef.Index >= (uint)this._capacity || this._info[entityRef.Index].Ref.Version != entityRef.Version)
        throw new InvalidOperationException(string.Format("{0} does not exist", (object)entityRef));
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void CheckComponentExistsAndThrowIfNot(int componentIndex)
    {
      if (componentIndex <= 0 || componentIndex >= this._componentBuffersLength)
        throw new IndexOutOfRangeException(string.Format("Component index '{0}' does not identify a valid component.",
          (object)componentIndex));
    }

    [Conditional("DEBUG")]
    private void AssertEntityComponentSetHasComponent(EntityRef entity, int index) =>
      Quantum.Assert.Check(this.GetComponentSetInternal(entity).IsSet(index));

    internal unsafe ComponentDataBuffer* GetDataBuffer<T>() where T : unmanaged, IComponent
    {
      ComponentDataBuffer* dataBuffer = this._componentBuffers + ComponentTypeId<T>.Id;
      Quantum.Assert.Check(dataBuffer->Stride == sizeof(T));
      return dataBuffer;
    }

    internal unsafe ComponentDataBuffer* GetDataBuffer(int index)
    {
      Quantum.Assert.Check((long)(uint)index < (long)this._componentBuffersLength);
      return this._componentBuffers + index;
    }

    internal unsafe ComponentSet GetComponentSetInternal(EntityRef entityRef) => this._componentMasks[entityRef.Index];

    private static int RoundToCulledByteSize(int size) => FrameBase.RoundToCulledWordCount(size) * 8;

    private static int RoundToCulledWordCount(int size) => (size + 63) / 64;

    public abstract unsafe Quantum.PhysicsSceneSettings* PhysicsSceneSettings { get; }

    public abstract Map Map { get; set; }

    public abstract unsafe Quantum.NavMeshRegionMask* NavMeshRegionMask { get; }

    public DynamicAssetDB DynamicAssetDB => this._dynamicAssetDB;

    public abstract unsafe Quantum.FrameMetaData* FrameMetaData { get; }

    /// <summary>Access to the Navigation API.</summary>
    /// 
    ///             \ingroup FrameClass
    public Navigation Navigation => this._context.Navigation;

    public LayerInfo Layers => this._context.Layers;

    public abstract int UpdateRate { get; }

    public abstract FP DeltaTime { get; set; }

    public FrameContext Context => this._context;

    public unsafe Quantum.Allocator.Heap* Heap => this._heap;

    protected unsafe FrameBase(FrameContext context)
    {
      Quantum.Assert.Check(context != null);
      this._context = context;
      this._heap = context.ReserveHeap();
      if (context.InitialDynamicAssets != null)
        this._dynamicAssetDB.CopyFrom(context.InitialDynamicAssets);
      this._dynamicAssetDB.StaticResourceManager = context.AssetDB.ResourceManager;
    }

    public override unsafe void Free()
    {
      this.Context.ReleaseHeap(this._heap);
      this.Context.Allocator.Free((void*)this._info);
      this.Context.Allocator.Free((void*)this._culled);
      this.Context.Allocator.Free((void*)this._sparse);
      this.Context.Allocator.Free((void*)this._componentMasks);
      for (int index = 1; index < this._componentBuffersLength; ++index)
        ComponentDataBuffer.Free(this.Context.Allocator, this._componentBuffers + index);
      this.Context.Allocator.Free((void*)this._componentBuffers);
      this.Unsafe.Dispose();
    }

    public unsafe FrameBase.Stats GetMemoryStats()
    {
      int num1 = 0;
      for (int index = 1; index < this._componentBuffersLength; ++index)
      {
        ComponentDataBuffer* componentDataBufferPtr = this._componentBuffers + index;
        num1 += componentDataBufferPtr->_blocksListCount * componentDataBufferPtr->_blockCapacity *
                componentDataBufferPtr->_stride;
      }

      int num2 = num1 + this._capacity * sizeof(EntityInfo) + this._capacity * 2 +
                 FrameBase.RoundToCulledByteSize(this._capacity);
      return new FrameBase.Stats()
      {
        HeapStats = Quantum.Allocator.Heap.GetStats(this._heap),
        EntityCount = this._usedCount - this._freeCount,
        EntityTotalMemory = num2
      };
    }

    internal unsafe QListInternal* ResolveList(Ptr ptr) => (QListInternal*)this._heap->Void(ptr);

    public unsafe QList<T> ResolveList<T>(QListPtr<T> ptr) where T : unmanaged =>
      new QList<T>(this._heap, (QListInternal*)this._heap->Void(ptr.Ptr));

    public unsafe QList<T> AllocateList<T>(int capacity = 8) where T : unmanaged =>
      QList<T>.Allocate(this._heap, capacity);

    public unsafe QList<T> AllocateList<T>(QListPtr<T> ptr, int capacity = 8) where T : unmanaged =>
      QList<T>.Allocate(this._heap, capacity);

    public void FreeList<T>(QListPtr<T> ptr) where T : unmanaged => this.ResolveList<T>(ptr).Free();

    public bool TryResolveList<T>(QListPtr<T> ptr, out QList<T> list) where T : unmanaged
    {
      if (ptr.Ptr == new Ptr())
      {
        list = new QList<T>();
        return false;
      }

      list = this.ResolveList<T>(ptr);
      return true;
    }

    public bool TryFreeList<T>(QListPtr<T> ptr) where T : unmanaged
    {
      if (ptr.Ptr == new Ptr())
        return false;
      this.FreeList<T>(ptr);
      return true;
    }

    internal unsafe QDictionaryInternal* ResolveDictionary(Ptr ptr) => (QDictionaryInternal*)this._heap->Void(ptr);

    public unsafe QDictionary<K, V> ResolveDictionary<K, V>(QDictionaryPtr<K, V> ptr)
      where K : unmanaged, IEquatable<K>
      where V : unmanaged
    {
      return new QDictionary<K, V>(this._heap, (QDictionaryInternal*)this._heap->Void(ptr.Ptr));
    }

    public unsafe QDictionary<K, V> AllocateDictionary<K, V>(int capacity = 8)
      where K : unmanaged, IEquatable<K>
      where V : unmanaged
    {
      return QDictionary<K, V>.Allocate(this._heap, capacity);
    }

    public unsafe QDictionary<K, V> AllocateDictionary<K, V>(QDictionaryPtr<K, V> ptr, int capacity = 8)
      where K : unmanaged, IEquatable<K>
      where V : unmanaged
    {
      return QDictionary<K, V>.Allocate(this._heap, capacity);
    }

    public bool TryResolveDictionary<K, V>(
      QDictionaryPtr<K, V> ptr,
      out QDictionary<K, V> dictionary)
      where K : unmanaged, IEquatable<K>
      where V : unmanaged
    {
      if (ptr.Ptr == new Ptr())
      {
        dictionary = new QDictionary<K, V>();
        return false;
      }

      dictionary = this.ResolveDictionary<K, V>(ptr);
      return true;
    }

    public unsafe QEnumDictionary<K, V> ResolveDictionary<K, V>(
      QDictionaryPtr<K, V> ptr,
      EnumEqualityComparer.Tag _ = default(EnumEqualityComparer.Tag))
      where K : unmanaged, Enum
      where V : unmanaged
    {
      return new QEnumDictionary<K, V>(this._heap, (QDictionaryInternal*)this._heap->Void(ptr.Ptr));
    }

    public unsafe QEnumDictionary<K, V> AllocateDictionary<K, V>(
      int capacity = 8,
      EnumEqualityComparer.Tag _ = default(EnumEqualityComparer.Tag))
      where K : unmanaged, Enum
      where V : unmanaged
    {
      return QEnumDictionary<K, V>.Allocate(this._heap, capacity);
    }

    public unsafe QEnumDictionary<K, V> AllocateDictionary<K, V>(
      QDictionaryPtr<K, V> ptr,
      int capacity = 8,
      EnumEqualityComparer.Tag _ = default(EnumEqualityComparer.Tag))
      where K : unmanaged, Enum
      where V : unmanaged
    {
      return QEnumDictionary<K, V>.Allocate(this._heap, capacity);
    }

    public bool TryResolveDictionary<K, V>(
      QDictionaryPtr<K, V> ptr,
      out QEnumDictionary<K, V> dictionary)
      where K : unmanaged, Enum
      where V : unmanaged
    {
      if (ptr.Ptr == new Ptr())
      {
        dictionary = new QEnumDictionary<K, V>();
        return false;
      }

      dictionary = this.ResolveDictionary<K, V>(ptr, new EnumEqualityComparer.Tag());
      return true;
    }

    public unsafe void FreeDictionary<K, V>(QDictionaryPtr<K, V> ptr)
      where K : unmanaged
      where V : unmanaged
    {
      QDictionaryInternal.Free(this._heap, this.ResolveDictionary(ptr.Ptr));
    }

    public bool TryFreeDictionary<K, V>(QDictionaryPtr<K, V> ptr)
      where K : unmanaged
      where V : unmanaged
    {
      if (ptr.Ptr == new Ptr())
        return false;
      this.FreeDictionary<K, V>(ptr);
      return true;
    }

    internal unsafe QHashCollection* ResolveHashCollection(Ptr ptr) => (QHashCollection*)this._heap->Void(ptr);

    public unsafe QHashSet<T> ResolveHashSet<T>(QHashSetPtr<T> ptr) where T : unmanaged, IEquatable<T> =>
      new QHashSet<T>(this._heap, (QHashCollection*)this._heap->Void(ptr.Ptr));

    public unsafe QHashSet<T> AllocateHashSet<T>(int capacity = 8) where T : unmanaged, IEquatable<T> =>
      QHashSet<T>.Allocate(this._heap, capacity);

    public unsafe QHashSet<T> AllocateHashSet<T>(QHashSetPtr<T> ptr, int capacity = 8)
      where T : unmanaged, IEquatable<T> => QHashSet<T>.Allocate(this._heap, capacity);

    public void FreeHashSet<T>(QHashSetPtr<T> ptr) where T : unmanaged, IEquatable<T> =>
      this.ResolveHashSet<T>(ptr).Free();

    public bool TryResolveHashSet<T>(QHashSetPtr<T> ptr, out QHashSet<T> hashSet) where T : unmanaged, IEquatable<T>
    {
      if (ptr.Ptr == new Ptr())
      {
        hashSet = new QHashSet<T>();
        return false;
      }

      hashSet = this.ResolveHashSet<T>(ptr);
      return true;
    }

    public bool TryFreeHashSet<T>(QHashSetPtr<T> ptr) where T : unmanaged, IEquatable<T>
    {
      if (ptr.Ptr == new Ptr())
        return false;
      this.FreeHashSet<T>(ptr);
      return true;
    }

    public unsafe void OnFrameSimulateBegin()
    {
      this.FrameMetaData->FreeAllTrackedInternal(this);
      if (this.CommitCommandsMode == CommitCommandsModes.OnFrameSimulationBegin)
        this.CommitAllCommands();
      this.ClearCulledState();
    }

    public void OnFrameSimulateEnd()
    {
      if (this.CommitCommandsMode != CommitCommandsModes.OnFrameSimulationEnd)
        return;
      this.CommitAllCommands();
    }

    /// <summary>If the entity is prediction-culled.</summary>
    /// <param name="entityRef">The reference of the entity being checked.</param>
    /// <returns>True if the frame <see cref="P:Photon.Deterministic.DeterministicFrame.IsPredicted">is predicted</see>
    /// and the entity <see cref="M:Quantum.Core.FrameBase.IsCulled(Quantum.EntityRef)">is culled</see>. False otherwise.</returns>
    /// 
    ///             \ingroup Culling
    public bool Culled(EntityRef entityRef) => this.IsPredicted && this.IsCulled(entityRef);

    /// <summary>Gets the total count of T components</summary>
    /// <param name="includePendingRemoval">
    /// If the component entries that were removed but are not yet committed in memory should be considered.
    /// </param>
    /// <typeparam name="T">The component type</typeparam>
    /// <returns>Total count</returns>
    public unsafe int ComponentCount<T>(bool includePendingRemoval = false) where T : unmanaged, IComponent
    {
      ComponentDataBuffer* dataBuffer = this.GetDataBuffer<T>();
      return includePendingRemoval ? dataBuffer->Count : dataBuffer->UsedCount;
    }

    /// <summary>
    /// Gets the total count of components of a given index.
    /// See <see cref="T:Quantum.ComponentTypeId" /> and <see cref="T:Quantum.ComponentTypeId`1" /> to have access to component types metadata.
    /// </summary>
    /// <param name="includePendingRemoval">
    /// If the component entries that were removed but are not yet committed in memory should be considered.
    /// </param>
    /// <param name="componentIndex">The index of the component type</param>
    /// <returns>Total count</returns>
    public unsafe int ComponentCount(int componentIndex, bool includePendingRemoval = false)
    {
      ComponentDataBuffer* componentDataBufferPtr = this._componentBuffers + componentIndex;
      return includePendingRemoval ? componentDataBufferPtr->Count : componentDataBufferPtr->UsedCount;
    }

    /// <summary>Adds a default component to an entity.</summary>
    /// <typeparam name="T">Component type</typeparam>
    /// <param name="entity">Entity reference</param>
    /// 
    ///             Internally calls <see cref="M:Quantum.Core.FrameBase.Has``1(Quantum.EntityRef)" />
    ///  and <see cref="M:Quantum.Core.FrameBase.Set``1(Quantum.EntityRef,``0)" />
    /// <exception cref="T:System.InvalidOperationException">Thrown when the entity does not exist</exception>
    /// <exception cref="T:System.InvalidOperationException">Thrown when entity already has a component of the given type</exception>
    /// 
    ///             \ingroup EntityApi
    public AddResult Add<T>(EntityRef entity) where T : unmanaged, IComponent => this.Add<T>(entity, default(T));

    /// <summary>
    /// Checks if the entity contains a whole set of components.
    /// </summary>
    /// <param name="entityRef">Entity reference</param>
    /// <param name="set">Set of component types</param>
    /// <returns>True if the entity has all component types</returns>
    /// 
    ///             \ingroup EntityApi
    public bool Has(EntityRef entityRef, ComponentSet set) => this.GetComponentSet(entityRef).IsSupersetOf(in set);

    /// <summary>
    /// Adds a dynamic asset to the frame.
    /// Dynamic Asset DB generates and assigns Guids for dynamic assets, so <paramref name="asset" /> can not
    /// have <see cref="P:Quantum.AssetObject.Guid" /> set before calling this method.
    /// </summary>
    /// <param name="asset">Asset object</param>
    /// <returns>Asset id</returns>
    /// <example><code>
    /// PhysicsMaterial material = new PhysicsMaterial {
    ///   Restitution = 1,
    ///   FrictionCombineFunction = PhysicsCombineFunction.Average,
    ///   RestitutionCombineFunction = PhysicsCombineFunction.Average };
    /// var assetId = f.AddAsset(material);
    /// </code></example>
    public AssetGuid AddAsset(AssetObject asset)
    {
      AssetGuid assetGuid = this._dynamicAssetDB.AddAsset(asset);
      asset.Loaded((IResourceManager)this._dynamicAssetDB, this.Context.Allocator);
      return assetGuid;
    }

    /// <summary>
    /// Replaces a dynamic asset in the frame.
    /// Asset <paramref name="asset" /> can not have <see cref="P:Quantum.AssetObject.Path" /> or <see cref="P:Quantum.AssetObject.Guid" />
    /// set as it inherits both from the original asset.
    /// </summary>
    /// <param name="guid">Guid of an asset to be replaced</param>
    /// <param name="asset">Asset object</param>
    public void ReplaceAsset(AssetGuid guid, AssetObject asset)
    {
      this._dynamicAssetDB.ReplaceAsset(guid, asset);
      asset.Loaded(this.Context.AssetDB.ResourceManager, this.Context.Allocator);
    }

    /// <summary>Loads an asset asynchronously into memory.</summary>
    /// <param name="guid">Asset guid</param>
    /// 
    ///             Typically assets are loaded on demand. Use this method to preload assets.
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool LoadAsset(AssetGuid guid) => this.LoadAssetInternal(guid, true);

    /// <summary>Disposes an asset.</summary>
    /// <param name="guid">Asset guid</param>
    /// 
    ///             The actual releasing of the asset is postponed and usually is triggered from the main thread at a later time.
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool DisposeAsset(AssetGuid guid) => this.DisposeAssetInternal(guid);

    /// <summary>Disposes an asset.</summary>
    /// <param name="path">Unique asset path</param>
    /// <param name="dbType"></param>
    /// 
    ///             The actual releasing of the asset is postponed and usually is triggered from the main thread at a later time.
    public void DisposeAsset(string path, DatabaseType dbType = DatabaseType.AssetDB)
    {
      if ((dbType & DatabaseType.AssetDB) == DatabaseType.AssetDB)
        this.Context.AssetDB.ResourceManager.DisposeAsset(path);
      if ((dbType & DatabaseType.DynamicDB) != DatabaseType.DynamicDB)
        return;
      this._dynamicAssetDB.DisposeAsset(path);
    }

    /// <summary>
    /// Retrieves an asset either from the asset database or as an dynamic asset. In case of a missing asset
    /// logs a warning.
    /// </summary>
    /// <typeparam name="T">Asset type</typeparam>
    /// <param name="guid">Asset guid</param>
    /// <returns>Null if guid is not valid or not found, otherwise the requested asset object</returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public T FindAsset<T>(AssetGuid guid) where T : AssetObject => this.FindAssetInternal<T>(guid, true);

    /// <summary>
    /// Retrieves an asset either from the asset database or as an dynamic asset. In case of a missing asset
    /// logs a warning.
    /// </summary>
    /// <typeparam name="T">Asset type</typeparam>
    /// <param name="assetRef">Asset reference</param>
    /// <returns>Null if reference is not valid or not found, otherwise the requested asset object</returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public T FindAsset<T>(AssetRef assetRef) where T : AssetObject => this.FindAssetInternal<T>(assetRef.Id, true);

    /// <summary>
    /// Retrieves an asset either from the asset database or as an dynamic asset. In case of a missing asset
    /// logs a warning.
    /// </summary>
    /// <typeparam name="T">Asset type</typeparam>
    /// <param name="assetRef">Asset reference</param>
    /// <param name="asset">Null if reference is not valid or not found, otherwise the requested asset object.</param>
    /// <returns>True if guid is valid and an asset is found</returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool FindAsset<T>(AssetRef assetRef, out T asset) where T : AssetObject
    {
      asset = this.FindAssetInternal<T>(assetRef.Id, true);
      return (object)asset != null;
    }

    /// <summary>
    /// Retrieves an asset either from the asset database or as an dynamic asset.
    /// </summary>
    /// <typeparam name="T">Asset type</typeparam>
    /// <param name="guid">Asset guid</param>
    /// <param name="asset">Null if guid is not valid or not found, otherwise the requested asset object</param>
    /// <returns>True if guid is valid and an asset is found</returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool TryFindAsset<T>(AssetGuid guid, out T asset) where T : AssetObject =>
      this.TryFindAssetInternal<T>(guid, true, out asset);

    /// <summary>
    /// Retrieves an asset either from the asset database or as an dynamic asset.
    /// </summary>
    /// <typeparam name="TAssetRef">Asset ref type</typeparam>
    /// <typeparam name="T">Asset type</typeparam>
    /// <param name="assetRef">Asset reference</param>
    /// <param name="asset">Null if reference is not valid or not found, otherwise the requested asset object</param>
    /// <returns>True if reference is valid and an asset is found</returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public unsafe bool TryFindAsset<TAssetRef, T>(TAssetRef assetRef, out T asset)
      where TAssetRef : unmanaged, IAssetRef<T>
      where T : AssetObject
    {
      return this.TryFindAssetInternal<T>(((AssetRef*)&assetRef)->Id, true, out asset);
    }

    /// <summary>
    /// Retrieves an asset either from the asset database or as an dynamic asset.
    /// </summary>
    /// <typeparam name="T">Asset type</typeparam>
    /// <param name="assetRef">Asset reference</param>
    /// <param name="asset">Null if reference is not valid or not found, otherwise the requested asset object</param>
    /// <returns>True if reference is valid and an asset is found</returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool TryFindAsset<T>(AssetRef assetRef, out T asset) where T : AssetObject =>
      this.TryFindAssetInternal<T>(assetRef.Id, true, out asset);

    /// <summary>
    /// Retrieves an asset by path from selected databases. In case of a missing asset
    /// logs a warning.
    /// </summary>
    /// <typeparam name="T">Asset type</typeparam>
    /// <param name="path">Unique asset path</param>
    /// <param name="dbType">Type of the database to look in (AssetDB by default)</param>
    /// <returns>Null if the asset path can not be found, otherwise the requested asset object</returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public T FindAsset<T>(string path, DatabaseType dbType = DatabaseType.AssetDB) where T : AssetObject =>
      this.FindAssetInternal<T>(path, true, dbType);

    /// <summary>Retrieves an asset by path from selected databases.</summary>
    /// <typeparam name="T">Asset type</typeparam>
    /// <param name="path">Unique asset path</param>
    /// <param name="asset">Null if the path is not valid or not found, otherwise the requested asset object</param>
    /// <param name="dbType">Type of the database to look in (AssetDB by default)</param>
    /// <returns>True if the path is valid and an asset is found</returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool TryFindAsset<T>(string path, out T asset, DatabaseType dbType = DatabaseType.AssetDB)
      where T : AssetObject => this.TryFindAssetInternal<T>(path, true, dbType, out asset);

    /// <summary>
    /// 
    /// </summary>
    /// <param name="prototypeRef"></param>
    /// <returns></returns>
    public EntityPrototypeContainer FindPrototype(EntityPrototypeRef prototypeRef)
    {
      AssetObject asset = this.FindAsset<AssetObject>(prototypeRef.Asset.Id);
      if (asset == null)
        return (EntityPrototypeContainer)null;
      if (prototypeRef.InnerAssetId < 0)
        return asset is EntityPrototype entityPrototype
          ? entityPrototype.Container
          : throw new InvalidOperationException(string.Format(
            "Expected prototype master asset (id: {0}) type: {1}, but was {2}", (object)prototypeRef.Asset,
            (object)typeof(EntityPrototype), (object)asset.GetType()));
      if (!(asset is Map map))
        throw new InvalidOperationException(string.Format(
          "Expected prototype master asset (id: {0}) type: {1}, but was: {2}", (object)prototypeRef.Asset,
          (object)typeof(Map), (object)asset.GetType()));
      int innerAssetId = prototypeRef.InnerAssetId;
      int? length = map.MapEntities?.Length;
      int valueOrDefault = length.GetValueOrDefault();
      if (innerAssetId < valueOrDefault & length.HasValue)
        return map.MapEntities[prototypeRef.InnerAssetId];
      throw new InvalidOperationException(string.Format("Prototype index out of bounds in map {0}: {1} (max: {2})",
        (object)prototypeRef.Asset, (object)prototypeRef.InnerAssetId, (object)map.MapEntities?.Length));
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="prototypeRef"></param>
    /// <returns></returns>
    public ComponentPrototype FindPrototype(ComponentPrototypeRef prototypeRef) => this
      .FindPrototype(prototypeRef.EntityPrototypeRef)?.GetComponentPrototype(prototypeRef.ComponentTypeIndex);

    public T FindPrototype<T>(ComponentPrototypeRef prototypeRef) where T : ComponentPrototype
    {
      ComponentPrototype prototype1 = this.FindPrototype(prototypeRef);
      if (prototype1 is T prototype2)
        return prototype2;
      if (prototype1 != null)
        throw new InvalidOperationException(string.Format("Component type mismatch: expected {0}, got {1})",
          (object)typeof(T), (object)prototype1.GetType()));
      return default(T);
    }

    public unsafe TPrototype FindPrototype<TPrototypeRef, TPrototype>(TPrototypeRef prototypeRef)
      where TPrototypeRef : unmanaged, IComponentPrototypeRef<TPrototype>
      where TPrototype : ComponentPrototype
    {
      return this.FindPrototype<TPrototype>(*(ComponentPrototypeRef*)&prototypeRef);
    }

    public bool FindPrototype<TPrototypeRef, TPrototype>(
      TPrototypeRef prototypeRef,
      out TPrototype prototype)
      where TPrototypeRef : unmanaged, IComponentPrototypeRef<TPrototype>
      where TPrototype : ComponentPrototype
    {
      prototype = this.FindPrototype<TPrototypeRef, TPrototype>(prototypeRef);
      return (object)prototype != null;
    }

    /// <summary>
    /// If a navmesh region is toggled on/off is saved here. Call this method to reset every region state to be enabled again.
    /// </summary>
    public unsafe void ClearAllNavMeshRegions()
    {
      if ((IntPtr)this.NavMeshRegionMask == IntPtr.Zero)
        return;
      this.NavMeshRegionMask->Clear();
    }

    internal bool TryFindAssetInternal<T>(AssetGuid guid, bool isMainThread, out T asset) where T : AssetObject
    {
      if (!guid.IsValid)
      {
        asset = default(T);
        return false;
      }

      AssetObject assetObject = guid.IsDynamic
        ? this._dynamicAssetDB.FindAsset(guid)
        : this.Context.AssetDB.FindAsset(guid, isMainThread);
      asset = assetObject as T;
      return (object)asset != null;
    }

    internal T FindAssetInternal<T>(AssetGuid guid, bool isMainThread) where T : AssetObject
    {
      if (!guid.IsValid)
        return default(T);
      AssetObject assetObject = guid.IsDynamic
        ? this._dynamicAssetDB.FindAsset(guid)
        : this.Context.AssetDB.FindAsset(guid, isMainThread);
      if (assetObject == null)
      {
        FrameBase.LogAssetNotFound(guid, typeof(T));
        return default(T);
      }

      if (assetObject is T assetInternal)
        return assetInternal;
      FrameBase.LogAssetTypeMismatch(guid, typeof(T), assetObject.GetType());
      return default(T);
    }

    internal bool TryFindAssetInternal<T>(
      string path,
      bool isMainThread,
      DatabaseType dbType,
      out T asset)
      where T : AssetObject
    {
      if ((dbType & DatabaseType.AssetDB) == DatabaseType.AssetDB &&
          this.Context.AssetDB.FindAsset(path, isMainThread) is T asset1)
      {
        asset = asset1;
        return true;
      }

      if ((dbType & DatabaseType.DynamicDB) == DatabaseType.DynamicDB &&
          this._dynamicAssetDB.FindAsset(path) is T asset2)
      {
        asset = asset2;
        return true;
      }

      asset = default(T);
      return false;
    }

    internal T FindAssetInternal<T>(string path, bool isMainThread, DatabaseType dbType) where T : AssetObject
    {
      AssetObject assetObject1 = (AssetObject)null;
      AssetObject assetObject2 = (AssetObject)null;
      if ((dbType & DatabaseType.AssetDB) == DatabaseType.AssetDB)
      {
        assetObject1 = this.Context.AssetDB.FindAsset(path, isMainThread);
        if (assetObject1 is T assetInternal)
          return assetInternal;
      }

      if ((dbType & DatabaseType.DynamicDB) == DatabaseType.DynamicDB)
      {
        assetObject2 = this._dynamicAssetDB.FindAsset(path);
        if (assetObject2 is T assetInternal)
          return assetInternal;
      }

      if (assetObject1 == null && assetObject2 == null)
      {
        FrameBase.LogAssetNotFound(path, dbType, typeof(T));
      }
      else
      {
        if (assetObject1 != null)
          FrameBase.LogAssetTypeMismatch(path, DatabaseType.AssetDB, typeof(T), assetObject1.GetType());
        if (assetObject2 != null)
          FrameBase.LogAssetTypeMismatch(path, DatabaseType.DynamicDB, typeof(T), assetObject2.GetType());
      }

      return default(T);
    }

    private static void LogAssetNotFound(AssetGuid guid, Type assetType) => Quantum.Log.Warn(
      string.Format("Unable to find asset {0} ({1})", (object)guid, (object)assetType.FullName), Array.Empty<object>());

    private static void LogAssetNotFound(string path, DatabaseType databaseType, Type assetType) => Quantum.Log.Warn(
      string.Format("Unable to find asset by path \"{0}\" ({1}) ({2})", (object)path, (object)databaseType,
        (object)assetType.FullName), Array.Empty<object>());

    private static void LogAssetTypeMismatch(AssetGuid guid, Type expectedType, Type assetType) => Quantum.Log.Warn(
      string.Format("Asset {0} type mismatch: expected {1}, got {2}", (object)guid, (object)expectedType.FullName,
        (object)assetType.FullName), Array.Empty<object>());

    private static void LogAssetTypeMismatch(
      string path,
      DatabaseType databaseType,
      Type expectedType,
      Type assetType)
    {
      Quantum.Log.Warn(
        string.Format("Asset \"{0}\" ({1}) type mismatch: expected {2}, got {3}", (object)path, (object)databaseType,
          (object)expectedType.FullName, (object)assetType.FullName), Array.Empty<object>());
    }

    internal bool LoadAssetInternal(AssetGuid guid, bool isMainThread)
    {
      if (!guid.IsValid)
        return false;
      if (!guid.IsDynamic && this.Context.AssetDB.LoadAsset(guid, isMainThread))
        return true;
      Quantum.Log.Warn("Unable to load asset {0}", (object)guid);
      return false;
    }

    internal bool DisposeAssetInternal(AssetGuid guid)
    {
      if (!guid.IsValid)
        return false;
      bool flag = guid.IsDynamic
        ? this._dynamicAssetDB.DisposeAsset(guid)
        : this.Context.AssetDB.ResourceManager.DisposeAsset(guid);
      if (!flag)
        Quantum.Log.Warn("Unable to dispose asset {0}", (object)guid);
      return flag;
    }

    /// <summary>Global entities configuration</summary>
    [Serializable]
    public class EntitiesConfig
    {
      /// <summary>
      /// When "remove component" and "destroy entity" commands should be committed, effectively cleaning and freeing the data from components' buffers.
      /// <remarks>Both commands still take immediate effect from a semantic perspective, e.g.: checking if the entity exists will return false as soon as the "destroy entity" method is called.</remarks>
      /// <remarks>Commiting commands on <see cref="F:Quantum.CommitCommandsModes.OnFrameSimulationBegin" /> will ensure that performing Physics Queries is safe, even after the frame simulation ends (from Unity),
      /// but might result in a larger total amount of memory reserved in case many entities are destroyed AND created in the same frame (analogous for "component removal").</remarks>
      /// </summary>
      [Tooltip(
        "When remove-component and destroy-entity commands should be committed, effectively cleaning and freeing the data from components buffers.\nBoth commands still take immediate effect from a semantic perspective, e.g.: checking if the entity exists will return false as soon as the destroy-entity method is called.\nCommiting commands on OnFrameSimulationBegin will ensure that performing Physics Queries is safe, even after the frame simulation ends (from Unity), but might result in a larger total amount of memory reserved in case many entities are destroyed AND created in the same frame (analogous for component-removal).")]
      public CommitCommandsModes CommitCommandsMode = CommitCommandsModes.OnFrameSimulationBegin;

      /// <summary>
      /// The starting capacity of internal entity and component buffers
      /// </summary>
      [Tooltip("The starting capacity of internal entity and component buffers.\nDefault is 1024.")]
      public int DefaultEntityCapacity = 1024;

      /// <summary>
      /// Default value for how many components are stored together in a continuous block of memory
      /// </summary>
      [Tooltip(
        "Default value for how many components are stored together in a continuous block of memory.\nDefault is 128.")]
      public int DefaultComponentBlockCapacity = 128;

      /// <summary>
      /// Allows overriding config values on a per-component level
      /// </summary>
      [Tooltip("Allows overriding config values on a per-component level.")]
      public FrameBase.EntitiesConfig.ComponentBufferConfig[] ComponentTypeConfiguration;

      public int GetComponentBlockCapacity(Type type)
      {
        if (this.ComponentTypeConfiguration == null)
          return Math.Max(1, this.DefaultComponentBlockCapacity);
        FrameBase.EntitiesConfig.ComponentBufferConfig componentBufferConfig =
          ((IEnumerable<FrameBase.EntitiesConfig.ComponentBufferConfig>)this.ComponentTypeConfiguration)
          .FirstOrDefault<FrameBase.EntitiesConfig.ComponentBufferConfig>(
            (Func<FrameBase.EntitiesConfig.ComponentBufferConfig, bool>)(x => x.Name == type.Name));
        return componentBufferConfig.Name == null
          ? Math.Max(1, this.DefaultComponentBlockCapacity)
          : Math.Max(1, componentBufferConfig.ComponentBlockCapacity);
      }

      [Serializable]
      public struct ComponentBufferConfig
      {
        public string Name;
        public int ComponentBlockCapacity;
      }
    }

    public class Culling
    {
      private TaskDelegateHandle _cull2DTask;
      private TaskDelegateHandle _cull3DTask;
      private unsafe FrameBase.Culling.CullingData* _data;

      internal unsafe Culling(FrameContext context)
      {
        this._data = context.Allocator.AllocAndClear<FrameBase.Culling.CullingData>();
        context.TaskContext.RegisterDelegate(new TaskDelegate(FrameBase.Culling.Task_CullTransform2D),
          "PredictionCulling.2D", ref this._cull2DTask);
        context.TaskContext.RegisterDelegate(new TaskDelegate(FrameBase.Culling.Task_CullTransform3D),
          "PredictionCulling.3D", ref this._cull3DTask);
      }

      internal unsafe void Dispose(FrameContext context)
      {
        context.Allocator.Free((void*)this._data);
        this._data = (FrameBase.Culling.CullingData*)null;
      }

      public unsafe TaskHandle Schedule2D(FrameBase f, TaskHandle handle)
      {
        this._data->Transform2DSliceIndexer = new AtomicInt();
        return f.Context.TaskContext.AddThreadedTask(this._cull2DTask, (void*)&this._data->Transform2DSliceIndexer,
          handle);
      }

      public unsafe TaskHandle Schedule3D(FrameBase f, TaskHandle handle)
      {
        this._data->Transform3DSliceIndexer = new AtomicInt();
        return f.Context.TaskContext.AddThreadedTask(this._cull3DTask, (void*)&this._data->Transform3DSliceIndexer,
          handle);
      }

      private static unsafe void Task_CullTransform2D(
        FrameThreadSafe frame,
        int start,
        int end,
        void* arg)
      {
        FrameBase frame1 = (FrameBase)frame;
        ComponentDataBuffer* dataBuffer = frame1.GetDataBuffer<Transform2D>();
        if (dataBuffer->Count == 0)
          return;
        AtomicInt* arrayIndexer = (AtomicInt*)arg;
        TaskSlice* slices = stackalloc TaskSlice[frame1.Context.TaskContext.SlicePerThreadMaxCount];
        TaskSlicer taskSlicer = frame1.Context.TaskContext.SlicePerThread(arrayIndexer, dataBuffer->_count, slices);
        TaskSlice slice;
        while (taskSlicer.Next(out slice))
        {
          for (int index = Math.Max(1, slice.StartInclusive); index < slice.EndExclusive; ++index)
          {
            Transform2D* dataPointerByIndex = (Transform2D*)dataBuffer->GetDataPointerByIndex(index);
            if (!frame1.Context.InPredictionArea((DeterministicFrame)frame1, dataPointerByIndex->Position))
            {
              EntityRef entityRefByIndex = dataBuffer->GetEntityRefByIndex(index);
              EntityInfo* entityInfoPtr = frame1._info + entityRefByIndex.Index;
              Quantum.Assert.Check(frame1.Exists(entityRefByIndex));
              if ((entityInfoPtr->Flags & EntityFlags.NotCullable) == (EntityFlags)0)
              {
                long comparand;
                long num;
                do
                {
                  comparand = frame1._culled[entityRefByIndex.Index / 64];
                  num = comparand | 1L << entityRefByIndex.Index % 64;
                } while (Interlocked.CompareExchange(ref frame1._culled[entityRefByIndex.Index / 64], num, comparand) !=
                         comparand);
              }
            }
          }
        }
      }

      private static unsafe void Task_CullTransform3D(
        FrameThreadSafe frame,
        int start,
        int end,
        void* arg)
      {
        FrameBase frame1 = (FrameBase)frame;
        ComponentDataBuffer* dataBuffer = frame1.GetDataBuffer<Transform3D>();
        if (dataBuffer->Count == 0)
          return;
        AtomicInt* arrayIndexer = (AtomicInt*)arg;
        TaskSlice* slices = stackalloc TaskSlice[frame1.Context.TaskContext.SlicePerThreadMaxCount];
        TaskSlicer taskSlicer = frame1.Context.TaskContext.SlicePerThread(arrayIndexer, dataBuffer->_count, slices);
        TaskSlice slice;
        while (taskSlicer.Next(out slice))
        {
          for (int index = Math.Max(1, slice.StartInclusive); index < slice.EndExclusive; ++index)
          {
            Transform3D* dataPointerByIndex = (Transform3D*)dataBuffer->GetDataPointerByIndex(index);
            if (!frame1.Context.InPredictionArea((DeterministicFrame)frame1, dataPointerByIndex->Position))
            {
              EntityRef entityRefByIndex = dataBuffer->GetEntityRefByIndex(index);
              EntityInfo* entityInfoPtr = frame1._info + entityRefByIndex.Index;
              Quantum.Assert.Check(frame1.Exists(entityRefByIndex));
              if ((entityInfoPtr->Flags & EntityFlags.NotCullable) == (EntityFlags)0)
              {
                long comparand;
                long num;
                do
                {
                  comparand = frame1._culled[entityRefByIndex.Index / 64];
                  num = comparand | 1L << entityRefByIndex.Index % 64;
                } while (Interlocked.CompareExchange(ref frame1._culled[entityRefByIndex.Index / 64], num, comparand) !=
                         comparand);
              }
            }
          }
        }
      }

      private struct CullingData
      {
        public AtomicInt Transform2DSliceIndexer;
        public AtomicInt Transform3DSliceIndexer;
      }
    }

    public struct Stats
    {
      public Quantum.Allocator.Heap.Stats HeapStats;
      public int EntityCount;
      public int EntityTotalMemory;
    }

    /// <summary>
    /// Frame API to give access to C# unsafe pointers and advanced immediate operations.
    /// </summary>
    /// <remarks>Usage: Frame.Unsafe.Get</remarks>
    /// 
    ///             \ingroup FrameClass
    ///             \ingroup EntityApi
    public struct FrameBaseUnsafe : IDisposable
    {
      private FrameBase _f;
      private ReaderWriterLockSlim _rwLock;
      private Dictionary<Type, ComponentFilterStructMeta> _filterStructMetaLookup;

      public FrameBaseUnsafe(FrameBase frame)
      {
        this._f = frame;
        this._rwLock = new ReaderWriterLockSlim();
        this._filterStructMetaLookup = new Dictionary<Type, ComponentFilterStructMeta>();
      }

      /// <summary>
      /// Get a component iterator that cycles blocks of component pointers.
      /// </summary>
      /// <typeparam name="T">Component type</typeparam>
      /// <returns>Block iterator</returns>
      /// <example><code>
      /// var region = 1UL &lt;&lt; 1;
      /// var navMeshAgents = f.Unsafe.GetComponentBlockIterator&lt;NavMeshAgent&gt;();
      /// while (navMeshAgents.NextBlock(out EntityRef* entities, out NavMeshAgent* agents, out int count)) {
      ///   for (int i = 0; i&lt;count; i++) {
      ///     var entity = entities[i];
      ///     var agent = &amp;agents[i];
      ///     agent-&gt;SetNavMeshRegionActive(region, !agent-&gt;IsNavMeshRegionActive(region));
      ///    }
      /// }
      /// </code></example>
      public ComponentBlockIterator<T> GetComponentBlockIterator<T>() where T : unmanaged, IComponent =>
        this._f.GetComponentBlockIterator<T>();

      /// <summary>
      /// Get a component iterator that cycles blocks of component pointers, using a start offset and count
      /// </summary>
      /// <typeparam name="T">Component type</typeparam>
      /// <param name="offset">Offset of entities we want</param>
      /// <param name="count">How many entities we want</param>
      /// <returns>Block iterator</returns>
      /// <example><code>
      /// var region = 1UL &lt;&lt; 1;
      /// var navMeshAgents = f.Unsafe.GetComponentBlockIterator&lt;NavMeshAgent&gt;(32, 16);
      /// while (navMeshAgents.NextBlock(out EntityRef* entities, out NavMeshAgent* agents, out int count)) {
      ///   for (int i = 0; i&lt;count; i++) {
      ///     var entity = entities[i];
      ///     var agent =  &amp;agents[i];
      ///     agent-&gt;SetNavMeshRegionActive(region, !agent-&gt;IsNavMeshRegionActive(region));
      ///    }
      /// }
      /// </code></example>
      public ComponentBlockIterator<T> GetComponentBlockIterator<T>(int offset, int count)
        where T : unmanaged, IComponent => this._f.GetComponentBlockIterator<T>(offset, count);

      public ComponentFilterStruct<T> FilterStruct<T>(
        ComponentSet without = default(ComponentSet),
        ComponentSet any = default(ComponentSet),
        int? offset = null,
        int? count = null)
        where T : unmanaged
      {
        this._rwLock.EnterReadLock();
        ComponentFilterStructMeta meta;
        bool flag;
        try
        {
          flag = this._filterStructMetaLookup.TryGetValue(typeof(T), out meta);
        }
        finally
        {
          this._rwLock.ExitReadLock();
        }

        if (!flag)
        {
          this._rwLock.EnterWriteLock();
          try
          {
            if (!this._filterStructMetaLookup.TryGetValue(typeof(T), out meta))
              this._filterStructMetaLookup.Add(typeof(T), meta = ComponentFilterStructMeta.Create<T>());
          }
          finally
          {
            this._rwLock.ExitWriteLock();
          }
        }

        return new ComponentFilterStruct<T>(this._f, meta, without, any, offset, count);
      }

      public ComponentGetter<T> ComponentGetter<T>() where T : unmanaged
      {
        this._rwLock.EnterReadLock();
        ComponentFilterStructMeta meta;
        bool flag;
        try
        {
          flag = this._filterStructMetaLookup.TryGetValue(typeof(T), out meta);
        }
        finally
        {
          this._rwLock.ExitReadLock();
        }

        if (!flag)
        {
          this._rwLock.EnterWriteLock();
          try
          {
            if (!this._filterStructMetaLookup.TryGetValue(typeof(T), out meta))
              this._filterStructMetaLookup.Add(typeof(T), meta = ComponentFilterStructMeta.Create<T>());
          }
          finally
          {
            this._rwLock.ExitWriteLock();
          }
        }

        return new ComponentGetter<T>(meta);
      }

      /// <summary>
      /// Gets a pointer to a component that can be changed directly without writing the component back with <see cref="M:Quantum.Core.FrameBase.Set``1(Quantum.EntityRef,``0)" />.
      /// </summary>
      /// <typeparam name="T">Component type</typeparam>
      /// <param name="entityRef">Entity reference</param>
      /// <returns>Pointer to the requested component</returns>
      /// <exception cref="T:System.InvalidOperationException">Thrown when the entity does not exist</exception>
      /// <exception cref="T:System.InvalidOperationException">Thrown when the entity does have the requested component type.</exception>
      /// <para>Always check the availability of the component with <see cref="M:Quantum.Core.FrameBase.Has(Quantum.EntityRef,Quantum.ComponentSet)" /> before using this method.</para>
      /// 
      ///             \ingroup EntityApi
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe T* GetPointer<T>(EntityRef entityRef) where T : unmanaged, IComponent =>
        this._f.GetPointer<T>(entityRef);

      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe void* GetPointer(EntityRef entityRef, int componentIndex) =>
        this._f.GetPointer(entityRef, componentIndex);

      /// <summary>
      /// Similar to <see cref="M:Quantum.Core.FrameBase.FrameBaseUnsafe.GetPointer``1(Quantum.EntityRef)" /> but does not throw an exception if the component is not present.
      /// </summary>
      /// <typeparam name="T">Component type</typeparam>
      /// <param name="entityRef">Entity reference</param>
      /// <param name="value">Resulting component pointer of null if the component was not found</param>
      /// <returns>True if component was found</returns>
      /// <exception cref="T:System.InvalidOperationException">Thrown when the entity does not exist</exception>
      /// 
      ///             \ingroup EntityApi
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe bool TryGetPointer<T>(EntityRef entityRef, out T* value) where T : unmanaged, IComponent =>
        this._f.TryGetPointer<T>(entityRef, out value);

      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe bool TryGetPointer(EntityRef entityRef, int componentIndex, out void* value) =>
        this._f.TryGetPointer(entityRef, componentIndex, out value);

      /// <summary>
      /// Trigger the execution of entity and component deletion.
      /// </summary>
      public void CommitAllCommands() => this._f.CommitAllCommands();

      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe T* GetPointerSingleton<T>() where T : unmanaged, IComponentSingleton =>
        this._f.GetPointerSingleton<T>();

      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe void* GetPointerSingleton(Type componentType) =>
        this._f.GetPointerSingleton(ComponentTypeId.GetComponentIndex(componentType));

      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe void* GetPointerSingleton(int componentIndex) => this._f.GetPointerSingleton(componentIndex);

      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe bool TryGetPointerSingleton<T>(out T* component) where T : unmanaged, IComponentSingleton =>
        this._f.TryGetPointerSingleton<T>(out component);

      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe bool TryGetPointerSingleton<T>(Type componentType, out void* component) =>
        this._f.TryGetPointerSingleton(ComponentTypeId.GetComponentIndex(componentType), out component);

      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe bool TryGetPointerSingleton(int componentIndex, out void* component) =>
        this._f.TryGetPointerSingleton(componentIndex, out component);

      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe T* GetOrAddSingletonPointer<T>(EntityRef optionalAddTarget = default(EntityRef))
        where T : unmanaged, IComponentSingleton => this._f.GetOrAddSingletonPointer<T>(optionalAddTarget);

      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public unsafe void*
        GetOrAddSingletonPointer(int componentIndex, EntityRef optionalAddTarget = default(EntityRef)) =>
        this._f.GetOrAddSingletonPointer(componentIndex, optionalAddTarget);

      public void Dispose()
      {
        this._rwLock?.Dispose();
        this._rwLock = (ReaderWriterLockSlim)null;
      }
    }

    public unsafe delegate void ComponentReactiveCallbackInvoker(
      EntityRef entity,
      void* componentData);

    public delegate void EntityPrototypeMaterializedCallbackInvoker(
      EntityRef entity,
      EntityPrototypeRef entityPrototype);
  }
}
